summaryrefslogtreecommitdiff
path: root/dbus_bindings
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2017-11-05 13:08:09 +0000
committerSimon McVittie <smcv@collabora.com>2017-11-05 13:56:09 +0000
commit71a613348477336df175a45dd46f035def495115 (patch)
treeb81fa4ea44d30341eac6741648f31cfe186a2b68 /dbus_bindings
parentb4d2cded0f7584e9c9429790c841e926acd8a082 (diff)
Rename source directories for C code to silence an ImportWarning
Python warns that it is not importing these directories because they contain no __init__.py. Signed-off-by: Simon McVittie <smcv@collabora.com>
Diffstat (limited to 'dbus_bindings')
-rw-r--r--dbus_bindings/abstract.c841
-rw-r--r--dbus_bindings/bus.c199
-rw-r--r--dbus_bindings/bytes.c300
-rw-r--r--dbus_bindings/compat-internal.h32
-rw-r--r--dbus_bindings/conn-internal.h67
-rw-r--r--dbus_bindings/conn-methods.c1068
-rw-r--r--dbus_bindings/conn.c502
-rw-r--r--dbus_bindings/containers.c825
-rw-r--r--dbus_bindings/dbus_bindings-internal.h296
-rw-r--r--dbus_bindings/debug.c96
-rw-r--r--dbus_bindings/exceptions.c104
-rw-r--r--dbus_bindings/float.c156
-rw-r--r--dbus_bindings/generic.c61
-rw-r--r--dbus_bindings/int.c804
-rw-r--r--dbus_bindings/libdbusconn.c126
-rw-r--r--dbus_bindings/mainloop.c207
-rw-r--r--dbus_bindings/message-append.c1293
-rw-r--r--dbus_bindings/message-get-args.c558
-rw-r--r--dbus_bindings/message-internal.h49
-rw-r--r--dbus_bindings/message.c1110
-rw-r--r--dbus_bindings/module.c432
-rw-r--r--dbus_bindings/pending-call.c294
-rw-r--r--dbus_bindings/server.c618
-rw-r--r--dbus_bindings/signature.c257
-rw-r--r--dbus_bindings/string.c383
-rw-r--r--dbus_bindings/types-internal.h112
-rw-r--r--dbus_bindings/unixfd.c254
-rw-r--r--dbus_bindings/validation.c245
28 files changed, 11289 insertions, 0 deletions
diff --git a/dbus_bindings/abstract.c b/dbus_bindings/abstract.c
new file mode 100644
index 0000000..7bdf368
--- /dev/null
+++ b/dbus_bindings/abstract.c
@@ -0,0 +1,841 @@
+/* Subclasses of built-in Python types supporting extra D-Bus functionality.
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+/* Dict indexed by object IDs, whose values are nonzero variant levels
+ * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct).
+ *
+ * This is a strange way to store them, but adding a __dict__ to the offending
+ * objects seems even more error-prone, given that their sizes are variable!
+ */
+PyObject *_dbus_py_variant_levels = NULL;
+
+long
+dbus_py_variant_level_get(PyObject *obj)
+{
+ PyObject *vl_obj;
+ PyObject *key = PyLong_FromVoidPtr(obj);
+ long variant_level;
+
+ if (!key) {
+ return -1;
+ }
+
+ vl_obj = PyDict_GetItem(_dbus_py_variant_levels, key);
+ Py_CLEAR(key);
+
+ if (!vl_obj) {
+ /* PyDict_GetItem() does not set an exception when the key is missing.
+ * In our case, it just means that there was no entry in the variant
+ * dictionary for this object. Semantically, this is equivalent to a
+ * variant level of 0.
+ */
+ return 0;
+ }
+ variant_level = NATIVEINT_ASLONG(vl_obj);
+ if (variant_level == -1 && PyErr_Occurred()) {
+ /* variant_level < 0 can never be inserted into the dictionary; see
+ * dbus_py_variant_level_set() below. The semantics of setting
+ * variant_level < 0 is to delete it from the dictionary.
+ */
+ return -1;
+ }
+ assert(variant_level >= 0);
+ return variant_level;
+}
+
+dbus_bool_t
+dbus_py_variant_level_set(PyObject *obj, long variant_level)
+{
+ /* key is the object's ID (= pointer) to avoid referencing it */
+ PyObject *key = PyLong_FromVoidPtr(obj);
+
+ if (!key) {
+ return FALSE;
+ }
+
+ if (variant_level <= 0) {
+ if (PyDict_GetItem (_dbus_py_variant_levels, key)) {
+ if (PyDict_DelItem (_dbus_py_variant_levels, key) < 0) {
+ Py_CLEAR(key);
+ return FALSE;
+ }
+ }
+ }
+ else {
+ PyObject *vl_obj = NATIVEINT_FROMLONG(variant_level);
+ if (!vl_obj) {
+ Py_CLEAR(key);
+ return FALSE;
+ }
+ if (PyDict_SetItem(_dbus_py_variant_levels, key, vl_obj) < 0) {
+ Py_CLEAR(vl_obj);
+ Py_CLEAR(key);
+ return FALSE;
+ }
+ Py_CLEAR(vl_obj);
+ }
+ Py_CLEAR(key);
+ return TRUE;
+}
+
+PyObject *
+dbus_py_variant_level_getattro(PyObject *obj, PyObject *name)
+{
+ PyObject *key, *value;
+
+#ifdef PY3
+ if (PyUnicode_CompareWithASCIIString(name, "variant_level"))
+ return PyObject_GenericGetAttr(obj, name);
+#else
+ if (PyBytes_Check(name)) {
+ Py_INCREF(name);
+ }
+ else if (PyUnicode_Check(name)) {
+ name = PyUnicode_AsEncodedString(name, NULL, NULL);
+ if (!name) {
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "attribute name must be string");
+ return NULL;
+ }
+
+ if (strcmp(PyBytes_AS_STRING(name), "variant_level")) {
+ value = PyObject_GenericGetAttr(obj, name);
+ Py_CLEAR(name);
+ return value;
+ }
+
+ Py_CLEAR(name);
+#endif /* PY3 */
+
+ key = PyLong_FromVoidPtr(obj);
+
+ if (!key) {
+ return NULL;
+ }
+
+ value = PyDict_GetItem(_dbus_py_variant_levels, key);
+ Py_CLEAR(key);
+
+ if (!value)
+ return NATIVEINT_FROMLONG(0);
+ Py_INCREF(value);
+ return value;
+}
+
+/* To be invoked by destructors. Clear the variant level without touching the
+ * exception state */
+void
+dbus_py_variant_level_clear(PyObject *self)
+{
+ PyObject *et, *ev, *etb;
+
+ /* avoid clobbering any pending exception */
+ PyErr_Fetch(&et, &ev, &etb);
+ if (!dbus_py_variant_level_set(self, 0)) {
+ /* should never happen */
+ PyErr_WriteUnraisable(self);
+ }
+ PyErr_Restore(et, ev, etb);
+}
+
+#ifndef PY3
+/* Support code for int subclasses. ================================== */
+
+PyDoc_STRVAR(DBusPythonInt_tp_doc,\
+"Base class for int subclasses with a ``variant_level`` attribute.\n"
+"Do not rely on the existence of this class outside dbus-python.\n"
+);
+
+static PyMemberDef DBusPythonInt_tp_members[] = {
+ {"variant_level", T_LONG, offsetof(DBusPyIntBase, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static PyObject *
+DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyInt_Type.tp_new)(cls, args, NULL);
+ if (self) {
+ ((DBusPyIntBase *)self)->variant_level = variantness;
+ }
+ return self;
+}
+
+static PyObject *
+DBusPythonInt_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
+ long variant_level = ((DBusPyIntBase *)self)->variant_level;
+ PyObject *my_repr;
+
+ if (!parent_repr) return NULL;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+PyTypeObject DBusPyIntBase_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._IntBase",
+ sizeof(DBusPyIntBase),
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ DBusPythonInt_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DBusPythonInt_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ DBusPythonInt_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ DBusPythonInt_tp_new, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+#endif /* !PY3 */
+
+/* Support code for float subclasses. ================================ */
+
+/* There's only one subclass at the moment (Double) but these are factored
+out to make room for Float later. (Float is implemented and #if'd out) */
+
+PyDoc_STRVAR(DBusPythonFloat_tp_doc,\
+"Base class for float subclasses with a ``variant_level`` attribute.\n"
+"Do not rely on the existence of this class outside dbus-python.\n"
+);
+
+static PyMemberDef DBusPythonFloat_tp_members[] = {
+ {"variant_level", T_LONG, offsetof(DBusPyFloatBase, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static PyObject *
+DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyFloat_Type.tp_new)(cls, args, NULL);
+ if (self) {
+ ((DBusPyFloatBase *)self)->variant_level = variantness;
+ }
+ return self;
+}
+
+static PyObject *
+DBusPythonFloat_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyFloat_Type.tp_repr)(self);
+ long variant_level = ((DBusPyFloatBase *)self)->variant_level;
+ PyObject *my_repr;
+
+ if (!parent_repr) return NULL;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+PyTypeObject DBusPyFloatBase_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._FloatBase",
+ sizeof(DBusPyFloatBase),
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ DBusPythonFloat_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DBusPythonFloat_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ DBusPythonFloat_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&PyFloat_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ DBusPythonFloat_tp_new, /* tp_new */
+};
+
+#ifdef PY3
+/* Support code for bytes subclasses ================================== */
+
+PyDoc_STRVAR(DBusPythonBytes_tp_doc,\
+"Base class for bytes subclasses with a ``variant_level`` attribute.\n"
+"Do not rely on the existence of this class outside dbus-python.\n"
+);
+
+static PyObject *
+DBusPythonBytes_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness))
+ return NULL;
+
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyBytes_Type.tp_new)(cls, args, NULL);
+ if (self) {
+ if (!dbus_py_variant_level_set(self, variantness)) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ }
+ return self;
+}
+
+static PyObject *
+DBusPythonBytes_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyBytes_Type.tp_repr)(self);
+ PyObject *vl_obj;
+ PyObject *my_repr;
+ long variant_level;
+
+ if (!parent_repr) return NULL;
+ vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
+ if (!vl_obj) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+ variant_level = NATIVEINT_ASLONG(vl_obj);
+ Py_CLEAR(vl_obj);
+ if (variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+static void
+DBusPyBytesBase_tp_dealloc(PyObject *self)
+{
+ dbus_py_variant_level_clear(self);
+ (PyBytes_Type.tp_dealloc)(self);
+}
+
+PyTypeObject DBusPyBytesBase_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._BytesBase",
+ 0,
+ 0,
+ DBusPyBytesBase_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ DBusPythonBytes_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ dbus_py_variant_level_getattro, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DBusPythonBytes_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&PyBytes_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ DBusPythonBytes_tp_new, /* tp_new */
+};
+#endif /* PY3 */
+
+/* Support code for str subclasses ================================== */
+
+PyDoc_STRVAR(DBusPythonString_tp_doc,\
+"Base class for str subclasses with a ``variant_level`` attribute.\n"
+"Do not rely on the existence of this class outside dbus-python.\n"
+);
+
+static PyObject *
+DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (NATIVESTR_TYPE.tp_new)(cls, args, NULL);
+ if (self) {
+ if (!dbus_py_variant_level_set(self, variantness)) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ }
+ return self;
+}
+
+static PyObject *
+DBusPythonString_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (NATIVESTR_TYPE.tp_repr)(self);
+ PyObject *vl_obj;
+ PyObject *my_repr;
+ long variant_level;
+
+ if (!parent_repr) return NULL;
+ vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
+ if (!vl_obj) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+ variant_level = NATIVEINT_ASLONG(vl_obj);
+ Py_CLEAR(vl_obj);
+ if (variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+static void
+DBusPyStrBase_tp_dealloc(PyObject *self)
+{
+ dbus_py_variant_level_clear(self);
+ (NATIVESTR_TYPE.tp_dealloc)(self);
+}
+
+PyTypeObject DBusPyStrBase_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._StrBase",
+ 0,
+ 0,
+ DBusPyStrBase_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ DBusPythonString_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ dbus_py_variant_level_getattro, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DBusPythonString_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&NATIVESTR_TYPE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ DBusPythonString_tp_new, /* tp_new */
+};
+
+/* Support code for long subclasses ================================= */
+
+PyDoc_STRVAR(DBusPythonLong_tp_doc,\
+"Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
+"Do not rely on the existence of this class outside dbus-python.\n"
+);
+
+static PyObject *
+DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyLong_Type.tp_new)(cls, args, NULL);
+ if (self) {
+ if (!dbus_py_variant_level_set(self, variantness)) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ }
+ return self;
+}
+
+static PyObject *
+DBusPythonLong_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
+ PyObject *vl_obj;
+ PyObject *my_repr;
+ long variant_level;
+
+ if (!parent_repr) return NULL;
+ vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
+ if (!vl_obj) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+ variant_level = NATIVEINT_ASLONG(vl_obj);
+ Py_CLEAR(vl_obj);
+ if (variant_level < 0 && PyErr_Occurred()) {
+ Py_CLEAR(parent_repr);
+ return NULL;
+ }
+
+ if (variant_level) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+static void
+DBusPyLongBase_tp_dealloc(PyObject *self)
+{
+ dbus_py_variant_level_clear(self);
+ (PyLong_Type.tp_dealloc)(self);
+}
+
+PyTypeObject DBusPyLongBase_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._LongBase",
+ 0,
+ 0,
+ DBusPyLongBase_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ DBusPythonLong_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ dbus_py_variant_level_getattro, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DBusPythonLong_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&PyLong_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ DBusPythonLong_tp_new, /* tp_new */
+};
+
+PyObject *dbus_py_variant_level_const = NULL;
+PyObject *dbus_py_signature_const = NULL;
+PyObject *dbus_py__dbus_object_path__const = NULL;
+
+#ifdef PY3
+#define INTERN (PyUnicode_InternFromString)
+#else
+/* Neither Python 2.6 nor 2.7 define the expected PyBytes_InternFromString
+ * alias in bytesobject.h.
+ */
+#define INTERN (PyString_InternFromString)
+#endif
+
+dbus_bool_t
+dbus_py_init_abstract(void)
+{
+ _dbus_py_variant_levels = PyDict_New();
+ if (!_dbus_py_variant_levels) return 0;
+
+ dbus_py__dbus_object_path__const = INTERN("__dbus_object_path__");
+ if (!dbus_py__dbus_object_path__const) return 0;
+
+ dbus_py_variant_level_const = INTERN("variant_level");
+ if (!dbus_py_variant_level_const) return 0;
+
+ dbus_py_signature_const = INTERN("signature");
+ if (!dbus_py_signature_const) return 0;
+
+#ifdef PY3
+ DBusPyBytesBase_Type.tp_base = &PyBytes_Type;
+ if (PyType_Ready(&DBusPyBytesBase_Type) < 0) return 0;
+ DBusPyBytesBase_Type.tp_print = NULL;
+#else
+ DBusPyIntBase_Type.tp_base = &PyInt_Type;
+ if (PyType_Ready(&DBusPyIntBase_Type) < 0) return 0;
+ /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
+ desired */
+ DBusPyIntBase_Type.tp_print = NULL;
+#endif
+
+ DBusPyFloatBase_Type.tp_base = &PyFloat_Type;
+ if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0;
+ DBusPyFloatBase_Type.tp_print = NULL;
+
+ DBusPyLongBase_Type.tp_base = &PyLong_Type;
+ if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0;
+ DBusPyLongBase_Type.tp_print = NULL;
+
+ DBusPyStrBase_Type.tp_base = &NATIVESTR_TYPE;
+ if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0;
+ DBusPyStrBase_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_abstract_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+#ifdef PY3
+ Py_INCREF(&DBusPyBytesBase_Type);
+ if (PyModule_AddObject(this_module, "_BytesBase",
+ (PyObject *)&DBusPyBytesBase_Type) < 0) return 0;
+#else
+ Py_INCREF(&DBusPyIntBase_Type);
+ if (PyModule_AddObject(this_module, "_IntBase",
+ (PyObject *)&DBusPyIntBase_Type) < 0) return 0;
+#endif
+ Py_INCREF(&DBusPyLongBase_Type);
+ Py_INCREF(&DBusPyStrBase_Type);
+ Py_INCREF(&DBusPyFloatBase_Type);
+ if (PyModule_AddObject(this_module, "_LongBase",
+ (PyObject *)&DBusPyLongBase_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "_StrBase",
+ (PyObject *)&DBusPyStrBase_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "_FloatBase",
+ (PyObject *)&DBusPyFloatBase_Type) < 0) return 0;
+
+ return 1;
+}
diff --git a/dbus_bindings/bus.c b/dbus_bindings/bus.c
new file mode 100644
index 0000000..ef257f3
--- /dev/null
+++ b/dbus_bindings/bus.c
@@ -0,0 +1,199 @@
+/* Implementation of Bus, a subtype of Connection.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "conn-internal.h"
+
+PyObject *
+DBusPyConnection_NewForBus(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *first = NULL, *mainloop = NULL;
+ DBusConnection *conn;
+ DBusError error;
+ Connection *self;
+ static char *argnames[] = {"address_or_type", "mainloop", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", argnames,
+ &first, &mainloop)) {
+ return NULL;
+ }
+
+ dbus_error_init(&error);
+
+ if (first &&
+#ifdef PY3
+ PyUnicode_Check(first)
+#else
+ PyBytes_Check(first)
+#endif
+ )
+ {
+ dbus_bool_t ret;
+
+ /* It's a custom address. First connect to it, then register. */
+
+ self = (Connection *)(DBusPyConnection_Type.tp_new)(cls, args, kwargs);
+ if (!self) return NULL;
+ TRACE(self);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_bus_register(self->conn, &error);
+ Py_END_ALLOW_THREADS
+ if (!ret) {
+ DBusPyException_ConsumeError(&error);
+ Py_CLEAR(self);
+ return NULL;
+ }
+
+ return (PyObject *)self;
+ }
+ else if (!first || INTORLONG_CHECK(first))
+ {
+ long type;
+ PyObject *libdbusconn;
+ PyObject *new_args;
+ PyObject *new_kwargs;
+
+ /* If the first argument isn't a string, it must be an integer
+ representing one of the well-known bus types. The default is
+ DBUS_BUS_SESSION. */
+
+ if (first) {
+ /* on Python 2 this accepts either int or long */
+ type = PyLong_AsLong(first);
+ if (type == -1 && PyErr_Occurred())
+ return NULL;
+
+ if (type != DBUS_BUS_SESSION && type != DBUS_BUS_SYSTEM
+ && type != DBUS_BUS_STARTER) {
+ PyErr_Format(PyExc_ValueError, "Unknown bus type %ld", type);
+ return NULL;
+ }
+ }
+ else {
+ type = DBUS_BUS_SESSION;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ conn = dbus_bus_get_private(type, &error);
+ Py_END_ALLOW_THREADS
+
+ if (!conn) {
+ DBusPyException_ConsumeError(&error);
+ return NULL;
+ }
+
+ libdbusconn = DBusPyLibDBusConnection_New (conn);
+ dbus_connection_unref (conn);
+
+ if (!libdbusconn)
+ return NULL;
+
+ new_args = PyTuple_Pack(2, libdbusconn, mainloop ? mainloop : Py_None);
+ Py_CLEAR(libdbusconn);
+
+ if (!new_args) {
+ return NULL;
+ }
+
+ new_kwargs = PyDict_New();
+
+ if (!new_kwargs) {
+ Py_CLEAR(new_args);
+ return NULL;
+ }
+
+ self = (Connection *)(DBusPyConnection_Type.tp_new)(cls, new_args,
+ new_kwargs);
+ Py_CLEAR(new_args);
+ Py_CLEAR(new_kwargs);
+
+ return (PyObject *)self; /* whether NULL or not */
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "A string address or an integer "
+ "bus type is required");
+ return NULL;
+ }
+}
+
+PyObject *
+DBusPyConnection_GetUniqueName(Connection *self, PyObject *args UNUSED)
+{
+ const char *name;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ name = dbus_bus_get_unique_name(self->conn);
+ Py_END_ALLOW_THREADS
+ if (!name) {
+ return DBusPyException_SetString("This connection has no unique name "
+ "yet");
+ }
+ return NATIVESTR_FROMSTR(name);
+}
+
+PyObject *
+DBusPyConnection_SetUniqueName(Connection *self, PyObject *args)
+{
+ const char *old_name, *new_name;
+
+ if (!PyArg_ParseTuple(args, "s:set_unique_name", &new_name)) {
+ return NULL;
+ }
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+
+ /* libdbus will assert if we try to set a unique name when there's
+ * already one, so we need to make sure that can't happen.
+ * (Thanks, libdbus.)
+ *
+ * The things that can set the unique name are:
+ * - this function - but we don't release the GIL, so only one instance of
+ * this function can run
+ * - dbus_bus_get - but this is only called in a __new__ or __new__-like
+ * function, so the new connection isn't available to other code yet
+ * and this function can't be called on it
+ * - dbus_bus_register - same as dbus_bus_get
+ *
+ * Code outside dbus-python shouldn't be setting the unique name, because
+ * we're using a private connection; we have to trust the authors
+ * of mainloop bindings not to do silly things like that.
+ */
+ old_name = dbus_bus_get_unique_name(self->conn);
+ if (old_name != NULL) {
+ PyErr_Format(PyExc_ValueError, "This connection already has a "
+ "unique name: '%s'", old_name);
+ return NULL;
+ }
+ dbus_bus_set_unique_name(self->conn, new_name);
+
+ Py_RETURN_NONE;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/bytes.c b/dbus_bindings/bytes.c
new file mode 100644
index 0000000..b0ff817
--- /dev/null
+++ b/dbus_bindings/bytes.c
@@ -0,0 +1,300 @@
+/* D-Bus Byte and ByteArray types.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+#ifdef PY3
+#define DBUS_PY_BYTE_BASE (DBusPyLongBase_Type)
+#else
+#define DBUS_PY_BYTE_BASE (DBusPyIntBase_Type)
+#endif
+
+PyDoc_STRVAR(Byte_tp_doc,
+"An unsigned byte: a subtype of int, with range restricted to [0, 255].\n"
+"\n"
+"A Byte b may be converted to a str of length 1 via str(b) == chr(b).\n"
+"\n"
+"Most of the time you don't want to use this class - it mainly exists\n"
+"for symmetry with the other D-Bus types. See `dbus.ByteArray` for a\n"
+"better way to handle arrays of Byte.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Byte(integer or str of length 1[, variant_level])\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a byte, this is represented in Python by a\n"
+" Byte with variant_level==2.\n"
+);
+
+static PyObject *
+Byte_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj;
+ PyObject *tuple;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError, "Byte constructor takes no more "
+ "than one positional argument");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ /* obj is a borrowed reference. It gets turned into an owned reference on
+ * the good-path of the if-statements below.
+ */
+ obj = PyTuple_GetItem(args, 0);
+
+ if (PyBytes_Check(obj)) {
+ /* string of length 1, we hope */
+ if (PyBytes_GET_SIZE(obj) != 1) {
+ goto bad_arg;
+ }
+ obj = NATIVEINT_FROMLONG((unsigned char)(PyBytes_AS_STRING(obj)[0]));
+ if (!obj)
+ goto bad_arg;
+ }
+ else if (INTORLONG_CHECK(obj)) {
+ /* on Python 2 this accepts either int or long */
+ long i = PyLong_AsLong(obj);
+ long my_variant_level;
+
+ if (i == -1 && PyErr_Occurred())
+ goto bad_arg;
+
+#ifdef PY3
+ my_variant_level = dbus_py_variant_level_get(obj);
+ if (my_variant_level < 0)
+ return NULL;
+#else
+ my_variant_level = ((DBusPyIntBase *)obj)->variant_level;
+#endif
+ if (Py_TYPE(obj) == cls && my_variant_level == variantness) {
+ Py_INCREF(obj);
+ return obj;
+ }
+ if (i < 0 || i > 255) goto bad_range;
+ /* else make it a new reference */
+ Py_INCREF(obj);
+ }
+ else {
+ goto bad_arg;
+ }
+
+ /* The tuple steals the reference to obj. */
+ tuple = Py_BuildValue("(N)", obj);
+ if (!tuple) return NULL;
+
+ obj = DBUS_PY_BYTE_BASE.tp_new(cls, tuple, kwargs);
+ Py_CLEAR(tuple);
+ return obj;
+
+bad_arg:
+ PyErr_SetString(PyExc_TypeError, "Expected a bytes or str of length 1, "
+ "or an int in the range 0-255");
+ return NULL;
+bad_range:
+ PyErr_SetString(PyExc_ValueError, "Integer outside range 0-255");
+ return NULL;
+}
+
+static PyObject *
+Byte_tp_str(PyObject *self)
+{
+ long i = NATIVEINT_ASLONG(self);
+ unsigned char str[2] = { 0, 0 };
+
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ if (i < 0 || i > 255) {
+ PyErr_SetString(PyExc_RuntimeError, "Integer outside range 0-255");
+ return NULL;
+ }
+
+ str[0] = (unsigned char)i;
+ return PyUnicode_FromStringAndSize((char *)str, 1);
+}
+
+PyTypeObject DBusPyByte_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Byte",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ Byte_tp_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Byte_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBUS_PY_BYTE_BASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Byte_new, /* tp_new */
+};
+
+#ifdef PY3
+#define DBUS_PY_BYTEARRAY_BASE (DBusPyBytesBase_Type)
+#else
+#define DBUS_PY_BYTEARRAY_BASE (DBusPyStrBase_Type)
+#endif
+
+PyDoc_STRVAR(ByteArray_tp_doc,
+"ByteArray is a subtype of str which can be used when you want an\n"
+"efficient immutable representation of a D-Bus byte array (signature 'ay').\n"
+"\n"
+"By default, when byte arrays are converted from D-Bus to Python, they\n"
+"come out as a `dbus.Array` of `dbus.Byte`. This is just for symmetry with\n"
+"the other D-Bus types - in practice, what you usually want is the byte\n"
+"array represented as a string, using this class. To get this, pass the\n"
+"``byte_arrays=True`` keyword argument to any of these methods:\n"
+"\n"
+"* any D-Bus method proxy, or ``connect_to_signal``, on the objects returned\n"
+" by `Bus.get_object`\n"
+"* any D-Bus method on a `dbus.Interface`\n"
+"* `dbus.Interface.connect_to_signal`\n"
+"* `Bus.add_signal_receiver`\n"
+"\n"
+"Import via::\n"
+"\n"
+" from dbus import ByteArray\n"
+"\n"
+"Constructor::\n"
+"\n"
+" ByteArray(str)\n"
+);
+
+PyTypeObject DBusPyByteArray_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.ByteArray",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ByteArray_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBUS_PY_BYTEARRAY_BASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_byte_types(void)
+{
+ DBusPyByte_Type.tp_base = &DBUS_PY_BYTE_BASE;
+ if (PyType_Ready(&DBusPyByte_Type) < 0) return 0;
+ DBusPyByte_Type.tp_print = NULL;
+
+ DBusPyByteArray_Type.tp_base = &DBUS_PY_BYTEARRAY_BASE;
+ if (PyType_Ready(&DBusPyByteArray_Type) < 0) return 0;
+ DBusPyByteArray_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_byte_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyByte_Type);
+ if (PyModule_AddObject(this_module, "Byte",
+ (PyObject *)&DBusPyByte_Type) < 0) return 0;
+ Py_INCREF(&DBusPyByteArray_Type);
+ if (PyModule_AddObject(this_module, "ByteArray",
+ (PyObject *)&DBusPyByteArray_Type) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/compat-internal.h b/dbus_bindings/compat-internal.h
new file mode 100644
index 0000000..9b9dce4
--- /dev/null
+++ b/dbus_bindings/compat-internal.h
@@ -0,0 +1,32 @@
+/* Old D-Bus compatibility: implementation internals
+ *
+ * Copyright © 2006-2011 Collabora Ltd.
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBUS_BINDINGS_COMPAT_INTERNAL_H
+#define DBUS_BINDINGS_COMPAT_INTERNAL_H
+
+#include "dbus_bindings-internal.h"
+
+#endif
diff --git a/dbus_bindings/conn-internal.h b/dbus_bindings/conn-internal.h
new file mode 100644
index 0000000..f4c7a80
--- /dev/null
+++ b/dbus_bindings/conn-internal.h
@@ -0,0 +1,67 @@
+/* _dbus_bindings internal API. For use within _dbus_bindings only.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBUS_BINDINGS_CONN_H
+#define DBUS_BINDINGS_CONN_H
+
+#include "dbus_bindings-internal.h"
+
+typedef struct {
+ PyObject_HEAD
+ DBusConnection *conn;
+ /* A list of filter callbacks. */
+ PyObject *filters;
+ /* A dict mapping object paths to one of:
+ * - tuples (unregister_callback or None, message_callback)
+ * - None (meaning unregistration from libdbus is in progress and nobody
+ * should touch this entry til we're finished)
+ */
+ PyObject *object_paths;
+
+ /* Weak-references list to make Connections weakly referenceable */
+ PyObject *weaklist;
+
+ dbus_bool_t has_mainloop;
+} Connection;
+
+typedef struct {
+ PyObject_HEAD
+ DBusConnection *conn;
+} DBusPyLibDBusConnection;
+
+extern struct PyMethodDef DBusPyConnection_tp_methods[];
+extern DBusHandlerResult DBusPyConnection_HandleMessage(Connection *,
+ PyObject *,
+ PyObject *);
+extern PyObject *DBusPyConnection_ExistingFromDBusConnection(DBusConnection *);
+extern PyObject *DBusPyConnection_GetObjectPathHandlers(PyObject *self,
+ PyObject *path);
+
+extern PyObject *DBusPyConnection_NewForBus(PyTypeObject *cls, PyObject *args,
+ PyObject *kwargs);
+extern PyObject *DBusPyConnection_SetUniqueName(Connection *, PyObject *);
+extern PyObject *DBusPyConnection_GetUniqueName(Connection *, PyObject *);
+
+#endif
diff --git a/dbus_bindings/conn-methods.c b/dbus_bindings/conn-methods.c
new file mode 100644
index 0000000..424fdc4
--- /dev/null
+++ b/dbus_bindings/conn-methods.c
@@ -0,0 +1,1068 @@
+/* Implementation of normal Python-accessible methods on the _dbus_bindings
+ * Connection type; separated out to keep the file size manageable.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "conn-internal.h"
+
+static void
+_object_path_unregister(DBusConnection *conn, void *user_data)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ PyObject *tuple = NULL;
+ Connection *conn_obj = NULL;
+ PyObject *callable;
+
+ conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) goto out;
+ TRACE(conn_obj);
+
+ DBG("Connection at %p unregistering object path %s",
+ conn_obj, PyBytes_AS_STRING((PyObject *)user_data));
+ tuple = DBusPyConnection_GetObjectPathHandlers(
+ (PyObject *)conn_obj, (PyObject *)user_data);
+ if (!tuple) goto out;
+ if (tuple == Py_None) goto out;
+
+ DBG("%s", "... yes we have handlers for that object path");
+
+ /* 0'th item is the unregisterer (if that's a word) */
+ callable = PyTuple_GetItem(tuple, 0);
+ if (callable && callable != Py_None) {
+ DBG("%s", "... and we even have an unregisterer");
+ /* any return from the unregisterer is ignored */
+ Py_XDECREF(PyObject_CallFunctionObjArgs(callable, conn_obj, NULL));
+ }
+out:
+ Py_CLEAR(conn_obj);
+ Py_CLEAR(tuple);
+ /* the user_data (a Python str) is no longer ref'd by the DBusConnection */
+ Py_CLEAR(user_data);
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ }
+ PyGILState_Release(gil);
+}
+
+static DBusHandlerResult
+_object_path_message(DBusConnection *conn, DBusMessage *message,
+ void *user_data)
+{
+ DBusHandlerResult ret;
+ PyGILState_STATE gil = PyGILState_Ensure();
+ Connection *conn_obj = NULL;
+ PyObject *tuple = NULL;
+ PyObject *msg_obj;
+ PyObject *callable; /* borrowed */
+
+ dbus_message_ref(message);
+ msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
+ if (!msg_obj) {
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto out;
+ }
+
+ conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) {
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+ TRACE(conn_obj);
+
+ DBG("Connection at %p messaging object path %s",
+ conn_obj, PyBytes_AS_STRING((PyObject *)user_data));
+ DBG_DUMP_MESSAGE(message);
+ tuple = DBusPyConnection_GetObjectPathHandlers(
+ (PyObject *)conn_obj, (PyObject *)user_data);
+ if (!tuple || tuple == Py_None) {
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+
+ DBG("%s", "... yes we have handlers for that object path");
+
+ /* 1st item (0-based) is the message callback */
+ callable = PyTuple_GetItem(tuple, 1);
+ if (!callable) {
+ DBG("%s", "... error getting message handler from tuple");
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else if (callable == Py_None) {
+ /* there was actually no handler after all */
+ DBG("%s", "... but those handlers don't do messages");
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else {
+ DBG("%s", "... and we have a message handler for that object path");
+ ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
+ }
+
+out:
+ Py_CLEAR(msg_obj);
+ Py_CLEAR(conn_obj);
+ Py_CLEAR(tuple);
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ }
+ PyGILState_Release(gil);
+ return ret;
+}
+
+static const DBusObjectPathVTable _object_path_vtable = {
+ _object_path_unregister,
+ _object_path_message,
+};
+
+static DBusHandlerResult
+_filter_message(DBusConnection *conn, DBusMessage *message, void *user_data)
+{
+ DBusHandlerResult ret;
+ PyGILState_STATE gil = PyGILState_Ensure();
+ Connection *conn_obj = NULL;
+ PyObject *callable = NULL;
+ PyObject *msg_obj;
+#ifndef DBUS_PYTHON_DISABLE_CHECKS
+ Py_ssize_t i, size;
+#endif
+
+ dbus_message_ref(message);
+ msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
+ if (!msg_obj) {
+ DBG("%s", "OOM while trying to construct Message");
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto out;
+ }
+
+ conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) {
+ DBG("%s", "failed to traverse DBusConnection -> Connection weakref");
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+ TRACE(conn_obj);
+
+ /* The user_data is a pointer to a Python object. To avoid
+ * cross-library reference cycles, the DBusConnection isn't allowed
+ * to reference it. However, as long as the Connection is still
+ * alive, its ->filters list owns a reference to the same Python
+ * object, so the object should also still be alive.
+ *
+ * To ensure that this works, be careful whenever manipulating the
+ * filters list! (always put things in the list *before* giving
+ * them to libdbus, etc.)
+ */
+#ifdef DBUS_PYTHON_DISABLE_CHECKS
+ callable = (PyObject *)user_data;
+#else
+ size = PyList_GET_SIZE(conn_obj->filters);
+ for (i = 0; i < size; i++) {
+ callable = PyList_GET_ITEM(conn_obj->filters, i);
+ if (callable == user_data) {
+ Py_INCREF(callable);
+ break;
+ }
+ else {
+ callable = NULL;
+ }
+ }
+
+ if (!callable) {
+ DBG("... filter %p has vanished from ->filters, so not calling it",
+ user_data);
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+#endif
+
+ ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
+out:
+ Py_CLEAR(msg_obj);
+ Py_CLEAR(conn_obj);
+ Py_CLEAR(callable);
+ PyGILState_Release(gil);
+ return ret;
+}
+
+PyDoc_STRVAR(Connection__require_main_loop__doc__,
+"_require_main_loop()\n\n"
+"Raise an exception if this Connection is not bound to any main loop -\n"
+"in this state, asynchronous calls, receiving signals and exporting objects\n"
+"will not work.\n"
+"\n"
+"`dbus.mainloop.NULL_MAIN_LOOP` is treated like a valid main loop - if you're\n"
+"using that, you presumably know what you're doing.\n");
+static PyObject *
+Connection__require_main_loop (Connection *self, PyObject *args UNUSED)
+{
+ if (!self->has_mainloop) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "To make asynchronous calls, receive signals or "
+ "export objects, D-Bus connections must be attached "
+ "to a main loop by passing mainloop=... to the "
+ "constructor or calling "
+ "dbus.set_default_main_loop(...)");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Connection_close__doc__,
+"close()\n\n"
+"Close the connection.");
+static PyObject *
+Connection_close (Connection *self, PyObject *args UNUSED)
+{
+ TRACE(self);
+ /* Because the user explicitly asked to close the connection, we'll even
+ let them close shared connections. */
+ if (self->conn) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_close(self->conn);
+ Py_END_ALLOW_THREADS
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Connection_get_is_connected__doc__,
+"get_is_connected() -> bool\n\n"
+"Return true if this Connection is connected.\n");
+static PyObject *
+Connection_get_is_connected (Connection *self, PyObject *args UNUSED)
+{
+ dbus_bool_t ret;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_connection_get_is_connected(self->conn);
+ Py_END_ALLOW_THREADS
+ return PyBool_FromLong(ret);
+}
+
+PyDoc_STRVAR(Connection_get_is_authenticated__doc__,
+"get_is_authenticated() -> bool\n\n"
+"Return true if this Connection was ever authenticated.\n");
+static PyObject *
+Connection_get_is_authenticated (Connection *self, PyObject *args UNUSED)
+{
+ dbus_bool_t ret;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_connection_get_is_authenticated(self->conn);
+ Py_END_ALLOW_THREADS
+ return PyBool_FromLong(ret);
+}
+
+PyDoc_STRVAR(Connection_set_exit_on_disconnect__doc__,
+"set_exit_on_disconnect(bool)\n\n"
+"Set whether the C function ``_exit`` will be called when this Connection\n"
+"becomes disconnected. This will cause the program to exit without calling\n"
+"any cleanup code or exit handlers.\n"
+"\n"
+"The default is for this feature to be disabled for Connections and enabled\n"
+"for Buses.\n");
+static PyObject *
+Connection_set_exit_on_disconnect (Connection *self, PyObject *args)
+{
+ int exit_on_disconnect;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTuple(args, "i:set_exit_on_disconnect",
+ &exit_on_disconnect)) {
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_set_exit_on_disconnect(self->conn,
+ exit_on_disconnect ? 1 : 0);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Connection_send_message__doc__,
+"send_message(msg) -> long\n\n"
+"Queue the given message for sending, and return the message serial number.\n"
+"\n"
+":Parameters:\n"
+" `msg` : dbus.lowlevel.Message\n"
+" The message to be sent.\n"
+);
+static PyObject *
+Connection_send_message(Connection *self, PyObject *args)
+{
+ dbus_bool_t ok;
+ PyObject *obj;
+ DBusMessage *msg;
+ dbus_uint32_t serial;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
+
+ msg = DBusPyMessage_BorrowDBusMessage(obj);
+ if (!msg) return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_send(self->conn, msg, &serial);
+ Py_END_ALLOW_THREADS
+
+ if (!ok) {
+ return PyErr_NoMemory();
+ }
+
+ return PyLong_FromUnsignedLong(serial);
+}
+
+PyDoc_STRVAR(Connection_set_allow_anonymous__doc__,
+"set_allow_anonymous(bool)\n\n"
+"Allows anonymous clients. Call this on the server side of a connection in a on_connection_added callback"
+);
+static PyObject *
+Connection_set_allow_anonymous(Connection *self, PyObject *args)
+{
+ dbus_bool_t t;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTuple(args, "i", &t)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_set_allow_anonymous(self->conn, t ? 1 : 0);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+/* The timeout is in seconds here, since that's conventional in Python. */
+PyDoc_STRVAR(Connection_send_message_with_reply__doc__,
+"send_message_with_reply(msg, reply_handler, timeout_s=-1, "
+"require_main_loop=False) -> dbus.lowlevel.PendingCall\n\n"
+"Queue the message for sending; expect a reply via the returned PendingCall,\n"
+"which can also be used to cancel the pending call.\n"
+"\n"
+":Parameters:\n"
+" `msg` : dbus.lowlevel.Message\n"
+" The message to be sent\n"
+" `reply_handler` : callable\n"
+" Asynchronous reply handler: will be called with one positional\n"
+" parameter, a Message instance representing the reply.\n"
+" `timeout_s` : float\n"
+" If the reply takes more than this many seconds, a timeout error\n"
+" will be created locally and raised instead. If this timeout is\n"
+" negative (default), a sane default (supplied by libdbus) is used.\n"
+" `require_main_loop` : bool\n"
+" If True, raise RuntimeError if this Connection does not have a main\n"
+" loop configured. If False (default) and there is no main loop, you are\n"
+" responsible for calling block() on the PendingCall.\n"
+"\n"
+);
+static PyObject *
+Connection_send_message_with_reply(Connection *self, PyObject *args, PyObject *kw)
+{
+ dbus_bool_t ok;
+ double timeout_s = -1.0;
+ int timeout_ms;
+ PyObject *obj, *callable;
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+ int require_main_loop = 0;
+ static char *argnames[] = {"msg", "reply_handler", "timeout_s",
+ "require_main_loop", NULL};
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTupleAndKeywords(args, kw,
+ "OO|di:send_message_with_reply",
+ argnames,
+ &obj, &callable, &timeout_s,
+ &require_main_loop)) {
+ return NULL;
+ }
+ if (require_main_loop && !Connection__require_main_loop(self, NULL)) {
+ return NULL;
+ }
+
+ msg = DBusPyMessage_BorrowDBusMessage(obj);
+ if (!msg) return NULL;
+
+ if (timeout_s < 0) {
+ timeout_ms = -1;
+ }
+ else {
+ if (timeout_s > ((double)INT_MAX) / 1000.0) {
+ PyErr_SetString(PyExc_ValueError, "Timeout too long");
+ return NULL;
+ }
+ timeout_ms = (int)(timeout_s * 1000.0);
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_send_with_reply(self->conn, msg, &pending,
+ timeout_ms);
+ Py_END_ALLOW_THREADS
+
+ if (!ok) {
+ return PyErr_NoMemory();
+ }
+
+ if (!pending) {
+ /* connection is disconnected (doesn't return FALSE!) */
+ return DBusPyException_SetString ("Connection is disconnected - "
+ "unable to make method call");
+ }
+
+ return DBusPyPendingCall_ConsumeDBusPendingCall(pending, callable);
+}
+
+/* Again, the timeout is in seconds, since that's conventional in Python. */
+PyDoc_STRVAR(Connection_send_message_with_reply_and_block__doc__,
+"send_message_with_reply_and_block(msg, timeout_s=-1)"
+" -> dbus.lowlevel.Message\n\n"
+"Send the message and block while waiting for a reply.\n"
+"\n"
+"This does not re-enter the main loop, so it can lead to a deadlock, if\n"
+"the called method tries to make a synchronous call to a method in this\n"
+"application. As such, it's probably a bad idea.\n"
+"\n"
+":Parameters:\n"
+" `msg` : dbus.lowlevel.Message\n"
+" The message to be sent\n"
+" `timeout_s` : float\n"
+" If the reply takes more than this many seconds, a timeout error\n"
+" will be created locally and raised instead. If this timeout is\n"
+" negative (default), a sane default (supplied by libdbus) is used.\n"
+":Returns:\n"
+" A `dbus.lowlevel.Message` instance (probably a `dbus.lowlevel.MethodReturnMessage`) on success\n"
+":Raises dbus.DBusException:\n"
+" On error (including if the reply arrives but is an\n"
+" error message)\n"
+"\n"
+);
+static PyObject *
+Connection_send_message_with_reply_and_block(Connection *self, PyObject *args)
+{
+ double timeout_s = -1.0;
+ int timeout_ms;
+ PyObject *obj;
+ DBusMessage *msg, *reply;
+ DBusError error;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTuple(args, "O|d:send_message_with_reply_and_block", &obj,
+ &timeout_s)) {
+ return NULL;
+ }
+
+ msg = DBusPyMessage_BorrowDBusMessage(obj);
+ if (!msg) return NULL;
+
+ if (timeout_s < 0) {
+ timeout_ms = -1;
+ }
+ else {
+ if (timeout_s > ((double)INT_MAX) / 1000.0) {
+ PyErr_SetString(PyExc_ValueError, "Timeout too long");
+ return NULL;
+ }
+ timeout_ms = (int)(timeout_s * 1000.0);
+ }
+
+ dbus_error_init(&error);
+ Py_BEGIN_ALLOW_THREADS
+ reply = dbus_connection_send_with_reply_and_block(self->conn, msg,
+ timeout_ms, &error);
+ Py_END_ALLOW_THREADS
+
+ /* FIXME: if we instead used send_with_reply and blocked on the resulting
+ * PendingCall, then we could get all args from the error, not just
+ * the first */
+ if (!reply) {
+ return DBusPyException_ConsumeError(&error);
+ }
+ return DBusPyMessage_ConsumeDBusMessage(reply);
+}
+
+PyDoc_STRVAR(Connection_flush__doc__,
+"flush()\n\n"
+"Block until the outgoing message queue is empty.\n");
+static PyObject *
+Connection_flush (Connection *self, PyObject *args UNUSED)
+{
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_flush (self->conn);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+/* Unsupported:
+ * dbus_connection_preallocate_send
+ * dbus_connection_free_preallocated_send
+ * dbus_connection_send_preallocated
+ * dbus_connection_borrow_message
+ * dbus_connection_return_message
+ * dbus_connection_steal_borrowed_message
+ * dbus_connection_pop_message
+ */
+
+/* Non-main-loop handling not yet implemented: */
+ /* dbus_connection_read_write_dispatch */
+ /* dbus_connection_read_write */
+
+/* Main loop handling not yet implemented: */
+ /* dbus_connection_get_dispatch_status */
+ /* dbus_connection_dispatch */
+ /* dbus_connection_set_watch_functions */
+ /* dbus_connection_set_timeout_functions */
+ /* dbus_connection_set_wakeup_main_function */
+ /* dbus_connection_set_dispatch_status_function */
+
+/* Normally in Python this would be called fileno(), but I don't want to
+ * encourage people to select() on it */
+PyDoc_STRVAR(Connection_get_unix_fd__doc__,
+"get_unix_fd() -> int or None\n\n"
+"Get the connection's UNIX file descriptor, if any.\n\n"
+"This can be used for SELinux access control checks with ``getpeercon()``\n"
+"for example. **Do not** read or write to the file descriptor, or try to\n"
+"``select()`` on it.\n");
+static PyObject *
+Connection_get_unix_fd (Connection *self, PyObject *unused UNUSED)
+{
+ int fd;
+ dbus_bool_t ok;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_get_unix_fd (self->conn, &fd);
+ Py_END_ALLOW_THREADS
+ if (!ok) Py_RETURN_NONE;
+ return NATIVEINT_FROMLONG(fd);
+}
+
+PyDoc_STRVAR(Connection_get_peer_unix_user__doc__,
+"get_peer_unix_user() -> long or None\n\n"
+"Get the UNIX user ID at the other end of the connection, if it has been\n"
+"authenticated. Return None if this is a non-UNIX platform or the\n"
+"connection has not been authenticated.\n");
+static PyObject *
+Connection_get_peer_unix_user (Connection *self, PyObject *unused UNUSED)
+{
+ unsigned long uid;
+ dbus_bool_t ok;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_get_unix_user (self->conn, &uid);
+ Py_END_ALLOW_THREADS
+ if (!ok) Py_RETURN_NONE;
+ return PyLong_FromUnsignedLong (uid);
+}
+
+PyDoc_STRVAR(Connection_get_peer_unix_process_id__doc__,
+"get_peer_unix_process_id() -> long or None\n\n"
+"Get the UNIX process ID at the other end of the connection, if it has been\n"
+"authenticated. Return None if this is a non-UNIX platform or the\n"
+"connection has not been authenticated.\n");
+static PyObject *
+Connection_get_peer_unix_process_id (Connection *self, PyObject *unused UNUSED)
+{
+ unsigned long pid;
+ dbus_bool_t ok;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_get_unix_process_id (self->conn, &pid);
+ Py_END_ALLOW_THREADS
+ if (!ok) Py_RETURN_NONE;
+ return PyLong_FromUnsignedLong (pid);
+}
+
+/* TODO: wrap dbus_connection_set_unix_user_function Pythonically */
+
+PyDoc_STRVAR(Connection_add_message_filter__doc__,
+"add_message_filter(callable)\n\n"
+"Add the given message filter to the internal list.\n\n"
+"Filters are handlers that are run on all incoming messages, prior to the\n"
+"objects registered to handle object paths.\n"
+"\n"
+"Filters are run in the order that they were added. The same handler can\n"
+"be added as a filter more than once, in which case it will be run more\n"
+"than once. Filters added during a filter callback won't be run on the\n"
+"message being processed.\n"
+);
+static PyObject *
+Connection_add_message_filter(Connection *self, PyObject *callable)
+{
+ dbus_bool_t ok;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ /* The callable must be referenced by ->filters *before* it is
+ * given to libdbus, which does not own a reference to it.
+ */
+ if (PyList_Append(self->filters, callable) < 0) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_add_filter(self->conn, _filter_message, callable,
+ NULL);
+ Py_END_ALLOW_THREADS
+
+ if (!ok) {
+ Py_XDECREF(PyObject_CallMethod(self->filters, "remove", "(O)",
+ callable));
+ PyErr_NoMemory();
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Connection_remove_message_filter__doc__,
+"remove_message_filter(callable)\n\n"
+"Remove the given message filter (see `add_message_filter` for details).\n"
+"\n"
+":Raises LookupError:\n"
+" The given callable is not among the registered filters\n");
+static PyObject *
+Connection_remove_message_filter(Connection *self, PyObject *callable)
+{
+ PyObject *obj;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ /* It's safe to do this before removing it from libdbus, because
+ * the presence of callable in our arguments means we have a ref
+ * to it. */
+ obj = PyObject_CallMethod(self->filters, "remove", "(O)", callable);
+ if (!obj) return NULL;
+ Py_CLEAR(obj);
+
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_remove_filter(self->conn, _filter_message, callable);
+ Py_END_ALLOW_THREADS
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Connection__register_object_path__doc__,
+"register_object_path(path, on_message, on_unregister=None, fallback=False)\n"
+"\n"
+"Register a callback to be called when messages arrive at the given\n"
+"object-path. Used to export objects' methods on the bus in a low-level\n"
+"way. For the high-level interface to this functionality (usually\n"
+"recommended) see the `dbus.service.Object` base class.\n"
+"\n"
+":Parameters:\n"
+" `path` : str\n"
+" Object path to be acted on\n"
+" `on_message` : callable\n"
+" Called when a message arrives at the given object-path, with\n"
+" two positional parameters: the first is this Connection,\n"
+" the second is the incoming `dbus.lowlevel.Message`.\n"
+" `on_unregister` : callable or None\n"
+" If not None, called when the callback is unregistered.\n"
+" `fallback` : bool\n"
+" If True (the default is False), when a message arrives for a\n"
+" 'subdirectory' of the given path and there is no more specific\n"
+" handler, use this handler. Normally this handler is only run if\n"
+" the paths match exactly.\n"
+);
+static PyObject *
+Connection__register_object_path(Connection *self, PyObject *args,
+ PyObject *kwargs)
+{
+ dbus_bool_t ok;
+ int fallback = 0;
+ char *path_bytes;
+ PyObject *callbacks, *path, *tuple, *on_message, *on_unregister = Py_None;
+ static char *argnames[] = {"path", "on_message", "on_unregister",
+ "fallback", NULL};
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!Connection__require_main_loop(self, NULL)) {
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "OO|Oi:_register_object_path",
+ argnames,
+ &path,
+ &on_message, &on_unregister,
+ &fallback)) return NULL;
+
+ /* Take a reference to path, which we give away to libdbus in a moment.
+
+ Also, path needs to be a string (not a subclass which could do something
+ mad) to preserve the desirable property that the DBusConnection can
+ never strongly reference the Connection, even indirectly.
+ */
+ if (PyBytes_CheckExact(path)) {
+ Py_INCREF(path);
+ }
+ else if (PyUnicode_Check(path)) {
+ path = PyUnicode_AsUTF8String(path);
+ if (!path) return NULL;
+ }
+ else if (PyBytes_Check(path)) {
+ path = PyBytes_FromString(PyBytes_AS_STRING(path));
+ if (!path) return NULL;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "path must be a str, bytes, or unicode object");
+ return NULL;
+ }
+
+ path_bytes = PyBytes_AS_STRING(path);
+ if (!dbus_py_validate_object_path(path_bytes)) {
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ tuple = Py_BuildValue("(OO)", on_unregister, on_message);
+ if (!tuple) {
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ /* Guard against registering a handler that already exists. */
+ callbacks = PyDict_GetItem(self->object_paths, path);
+ if (callbacks && callbacks != Py_None) {
+ PyErr_Format(PyExc_KeyError, "Can't register the object-path "
+ "handler for '%s': there is already a handler",
+ path_bytes);
+ Py_CLEAR(tuple);
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ /* Pre-allocate a slot in the dictionary, so we know we'll be able
+ * to replace it with the callbacks without OOM.
+ * This ensures we can keep libdbus' opinion of whether those
+ * paths are handled in sync with our own. */
+ if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
+ Py_CLEAR(tuple);
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ if (fallback) {
+ ok = dbus_connection_register_fallback(self->conn,
+ path_bytes,
+ &_object_path_vtable,
+ path);
+ }
+ else {
+ ok = dbus_connection_register_object_path(self->conn,
+ path_bytes,
+ &_object_path_vtable,
+ path);
+ }
+ Py_END_ALLOW_THREADS
+
+ if (ok) {
+ if (PyDict_SetItem(self->object_paths, path, tuple) < 0) {
+ /* That shouldn't have happened, we already allocated enough
+ memory for it. Oh well, try to undo the registration to keep
+ things in sync. If this fails too, we've leaked a bit of
+ memory in libdbus, but tbh we should never get here anyway. */
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_unregister_object_path(self->conn,
+ path_bytes);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+ /* don't DECREF path: libdbus owns a ref now */
+ Py_CLEAR(tuple);
+ Py_RETURN_NONE;
+ }
+ else {
+ /* Oops, OOM. Tidy up, if we can, ignoring any error. */
+ PyDict_DelItem(self->object_paths, path);
+ PyErr_Clear();
+ Py_CLEAR(tuple);
+ Py_CLEAR(path);
+ PyErr_NoMemory();
+ return NULL;
+ }
+}
+
+PyDoc_STRVAR(Connection__unregister_object_path__doc__,
+"unregister_object_path(path)\n\n"
+"Remove a previously registered handler for the given object path.\n"
+"\n"
+":Parameters:\n"
+" `path` : str\n"
+" The object path whose handler is to be removed\n"
+":Raises KeyError: if there is no handler registered for exactly that\n"
+" object path.\n"
+);
+static PyObject *
+Connection__unregister_object_path(Connection *self, PyObject *args,
+ PyObject *kwargs)
+{
+ dbus_bool_t ok;
+ char *path_bytes;
+ PyObject *path;
+ PyObject *callbacks;
+ static char *argnames[] = {"path", NULL};
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O:_unregister_object_path",
+ argnames, &path)) return NULL;
+
+ /* Take a ref to the path. Same comments as for _register_object_path. */
+ if (PyBytes_CheckExact(path)) {
+ Py_INCREF(path);
+ }
+ else if (PyUnicode_Check(path)) {
+ path = PyUnicode_AsUTF8String(path);
+ if (!path) return NULL;
+ }
+ else if (PyBytes_Check(path)) {
+ path = PyBytes_FromString(PyBytes_AS_STRING(path));
+ if (!path) return NULL;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "path must be a str, bytes, or unicode object");
+ return NULL;
+ }
+
+ path_bytes = PyBytes_AS_STRING(path);
+
+ /* Guard against unregistering a handler that doesn't, in fact, exist,
+ or whose unregistration is already in progress. */
+ callbacks = PyDict_GetItem(self->object_paths, path);
+ if (!callbacks || callbacks == Py_None) {
+ PyErr_Format(PyExc_KeyError, "Can't unregister the object-path "
+ "handler for '%s': there is no such handler",
+ path_bytes);
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ /* Hang on to a reference to the callbacks for the moment. */
+ Py_INCREF(callbacks);
+
+ /* Get rid of the object-path while we still have the GIL, to
+ guard against unregistering twice from different threads (which
+ causes undefined behaviour in libdbus).
+
+ Because deletion would make it possible for the re-insertion below
+ to fail, we instead set the handler to None as a placeholder.
+ */
+ if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
+ /* If that failed, there's no need to be paranoid as below - the
+ callbacks are still set, so we failed, but at least everything
+ is in sync. */
+ Py_CLEAR(callbacks);
+ Py_CLEAR(path);
+ return NULL;
+ }
+
+ /* BEGIN PARANOIA
+ This is something of a critical section - the dict of object-paths
+ and libdbus' internal structures are out of sync for a bit. We have
+ to be able to cope with that.
+
+ It's really annoying that dbus_connection_unregister_object_path
+ can fail, *and* has undefined behaviour if the object path has
+ already been unregistered. Either/or would be fine.
+ */
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_unregister_object_path(self->conn, path_bytes);
+ Py_END_ALLOW_THREADS
+
+ if (ok) {
+ Py_CLEAR(callbacks);
+ PyDict_DelItem(self->object_paths, path);
+ /* END PARANOIA on successful code path */
+ /* The above can't fail unless by some strange trickery the key is no
+ longer present. Ignore any errors. */
+ Py_CLEAR(path);
+ PyErr_Clear();
+ Py_RETURN_NONE;
+ }
+ else {
+ /* Oops, OOM. Put the callbacks back in the dict so
+ * we'll have another go if/when the user frees some memory
+ * and tries calling this method again. */
+ PyDict_SetItem(self->object_paths, path, callbacks);
+ /* END PARANOIA on failing code path */
+ /* If the SetItem failed, there's nothing we can do about it - but
+ since we know it's an existing entry, it shouldn't be able to fail
+ anyway. */
+ Py_CLEAR(path);
+ Py_CLEAR(callbacks);
+ return PyErr_NoMemory();
+ }
+}
+
+PyDoc_STRVAR(Connection_list_exported_child_objects__doc__,
+"list_exported_child_objects(path: str) -> list of str\n\n"
+"Return a list of the names of objects exported on this Connection as\n"
+"direct children of the given object path.\n"
+"\n"
+"Each name returned may be converted to a valid object path using\n"
+"``dbus.ObjectPath('%s%s%s' % (path, (path != '/' and '/' or ''), name))``.\n"
+"For the purposes of this function, every parent or ancestor of an exported\n"
+"object is considered to be an exported object, even if it's only an object\n"
+"synthesized by the library to support introspection.\n");
+static PyObject *
+Connection_list_exported_child_objects (Connection *self, PyObject *args,
+ PyObject *kwargs)
+{
+ const char *path;
+ char **kids, **kid_ptr;
+ dbus_bool_t ok;
+ PyObject *ret;
+ static char *argnames[] = {"path", NULL};
+
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", argnames, &path)) {
+ return NULL;
+ }
+
+ if (!dbus_py_validate_object_path(path)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_list_registered(self->conn, path, &kids);
+ Py_END_ALLOW_THREADS
+
+ if (!ok) {
+ return PyErr_NoMemory();
+ }
+
+ ret = PyList_New(0);
+ if (!ret) {
+ return NULL;
+ }
+ for (kid_ptr = kids; *kid_ptr; kid_ptr++) {
+ PyObject *tmp = NATIVESTR_FROMSTR(*kid_ptr);
+
+ if (!tmp) {
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ if (PyList_Append(ret, tmp) < 0) {
+ Py_CLEAR(tmp);
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ Py_CLEAR(tmp);
+ }
+
+ dbus_free_string_array(kids);
+
+ return ret;
+}
+
+ /* dbus_connection_get_object_path_data - not useful to Python,
+ * the object path data is just a PyBytes containing the path */
+ /* dbus_connection_list_registered could be useful, though */
+
+/* dbus_connection_set_change_sigpipe - sets global state */
+
+/* Maxima. Does Python code ever need to manipulate these?
+ * OTOH they're easy to wrap */
+ /* dbus_connection_set_max_message_size */
+ /* dbus_connection_get_max_message_size */
+ /* dbus_connection_set_max_received_size */
+ /* dbus_connection_get_max_received_size */
+
+/* dbus_connection_get_outgoing_size - almost certainly unneeded */
+
+PyDoc_STRVAR(new_for_bus__doc__,
+"Connection._new_for_bus([address: str or int]) -> Connection\n"
+"\n"
+"If the address is an int it must be one of the constants BUS_SESSION,\n"
+"BUS_SYSTEM, BUS_STARTER; if a string, it must be a D-Bus address.\n"
+"The default is BUS_SESSION.\n"
+);
+
+PyDoc_STRVAR(get_unique_name__doc__,
+"get_unique_name() -> str\n\n"
+"Return this application's unique name on this bus.\n"
+"\n"
+":Raises DBusException: if the connection has no unique name yet\n"
+" (for Bus objects this can't happen, for peer-to-peer connections\n"
+" this means you haven't called `set_unique_name`)\n");
+
+PyDoc_STRVAR(set_unique_name__doc__,
+"set_unique_name(str)\n\n"
+"Set this application's unique name on this bus. Raise ValueError if it has\n"
+"already been set.\n");
+
+struct PyMethodDef DBusPyConnection_tp_methods[] = {
+#define ENTRY(name, flags) {#name, (PyCFunction)Connection_##name, flags, Connection_##name##__doc__}
+ ENTRY(_require_main_loop, METH_NOARGS),
+ ENTRY(close, METH_NOARGS),
+ ENTRY(flush, METH_NOARGS),
+ ENTRY(get_is_connected, METH_NOARGS),
+ ENTRY(get_is_authenticated, METH_NOARGS),
+ ENTRY(set_exit_on_disconnect, METH_VARARGS),
+ ENTRY(get_unix_fd, METH_NOARGS),
+ ENTRY(get_peer_unix_user, METH_NOARGS),
+ ENTRY(get_peer_unix_process_id, METH_NOARGS),
+ ENTRY(add_message_filter, METH_O),
+ ENTRY(_register_object_path, METH_VARARGS|METH_KEYWORDS),
+ ENTRY(remove_message_filter, METH_O),
+ ENTRY(send_message, METH_VARARGS),
+ ENTRY(send_message_with_reply, METH_VARARGS|METH_KEYWORDS),
+ ENTRY(send_message_with_reply_and_block, METH_VARARGS),
+ ENTRY(_unregister_object_path, METH_VARARGS|METH_KEYWORDS),
+ ENTRY(list_exported_child_objects, METH_VARARGS|METH_KEYWORDS),
+ {"_new_for_bus", (PyCFunction)DBusPyConnection_NewForBus,
+ METH_CLASS|METH_VARARGS|METH_KEYWORDS,
+ new_for_bus__doc__},
+ {"get_unique_name", (PyCFunction)DBusPyConnection_GetUniqueName,
+ METH_NOARGS,
+ get_unique_name__doc__},
+ {"set_unique_name", (PyCFunction)DBusPyConnection_SetUniqueName,
+ METH_VARARGS,
+ set_unique_name__doc__},
+ ENTRY(set_allow_anonymous, METH_VARARGS),
+ {NULL},
+#undef ENTRY
+};
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/conn.c b/dbus_bindings/conn.c
new file mode 100644
index 0000000..9ef1487
--- /dev/null
+++ b/dbus_bindings/conn.c
@@ -0,0 +1,502 @@
+/* Implementation of the _dbus_bindings Connection type, a Python wrapper
+ * for DBusConnection. See also conn-methods.c.
+ *
+ * Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "conn-internal.h"
+
+/* Connection definition ============================================ */
+
+PyDoc_STRVAR(Connection_tp_doc,
+"A D-Bus connection.\n"
+"\n"
+"::\n"
+"\n"
+" Connection(address, mainloop=None) -> Connection\n"
+);
+
+/* D-Bus Connection user data slot, containing an owned reference to either
+ * the Connection, or a weakref to the Connection.
+ */
+static dbus_int32_t _connection_python_slot;
+
+/* C API for main-loop hooks ======================================== */
+
+/* Return a borrowed reference to the DBusConnection which underlies this
+ * Connection. */
+DBusConnection *
+DBusPyConnection_BorrowDBusConnection(PyObject *self)
+{
+ DBusConnection *dbc;
+
+ TRACE(self);
+ if (!DBusPyConnection_Check(self)) {
+ PyErr_SetString(PyExc_TypeError, "A dbus.Connection is required");
+ return NULL;
+ }
+ dbc = ((Connection *)self)->conn;
+ if (!dbc) {
+ PyErr_SetString(PyExc_RuntimeError, "Connection is in an invalid "
+ "state: no DBusConnection");
+ return NULL;
+ }
+ return dbc;
+}
+
+/* Internal C API =================================================== */
+
+/* Pass a message through a handler. */
+DBusHandlerResult
+DBusPyConnection_HandleMessage(Connection *conn,
+ PyObject *msg,
+ PyObject *callable)
+{
+ PyObject *obj;
+
+ TRACE(conn);
+ obj = PyObject_CallFunctionObjArgs(callable, conn, msg,
+ NULL);
+ if (obj == Py_None) {
+ DBG("%p: OK, handler %p returned None", conn, callable);
+ Py_CLEAR(obj);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (obj == Py_NotImplemented) {
+ DBG("%p: handler %p returned NotImplemented, continuing",
+ conn, callable);
+ Py_CLEAR(obj);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else if (!obj) {
+ if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ DBG_EXC("%p: handler %p caused OOM", conn, callable);
+ PyErr_Clear();
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+ DBG_EXC("%p: handler %p raised exception", conn, callable);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else {
+ long i = PyLong_AsLong(obj);
+ DBG("%p: handler %p returned %ld", conn, callable, i);
+ Py_CLEAR(obj);
+ if (i == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Return from D-Bus message "
+ "handler callback should be None, "
+ "NotImplemented or integer");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else if (i == DBUS_HANDLER_RESULT_HANDLED ||
+ i == DBUS_HANDLER_RESULT_NOT_YET_HANDLED ||
+ i == DBUS_HANDLER_RESULT_NEED_MEMORY) {
+ return i;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "Integer return from "
+ "D-Bus message handler callback should "
+ "be a DBUS_HANDLER_RESULT_... constant, "
+ "not %d", (int)i);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ }
+}
+
+/* On KeyError or if unregistration is in progress, return None. */
+PyObject *
+DBusPyConnection_GetObjectPathHandlers(PyObject *self, PyObject *path)
+{
+ PyObject *callbacks;
+
+ TRACE(self);
+ callbacks = PyDict_GetItem(((Connection *)self)->object_paths, path);
+ if (!callbacks) {
+ if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ Py_RETURN_NONE;
+ }
+ }
+ Py_INCREF(callbacks);
+ return callbacks;
+}
+
+/* Return a new reference to a Python Connection or subclass corresponding
+ * to the DBusConnection conn. For use in callbacks.
+ *
+ * Raises AssertionError if the DBusConnection does not have a Connection.
+ */
+PyObject *
+DBusPyConnection_ExistingFromDBusConnection(DBusConnection *conn)
+{
+ PyObject *self, *ref;
+
+ Py_BEGIN_ALLOW_THREADS
+ ref = (PyObject *)dbus_connection_get_data(conn,
+ _connection_python_slot);
+ Py_END_ALLOW_THREADS
+ if (ref) {
+ DBG("(DBusConnection *)%p has weak reference at %p", conn, ref);
+ self = PyWeakref_GetObject(ref); /* still a borrowed ref */
+ if (self && self != Py_None && DBusPyConnection_Check(self)) {
+ DBG("(DBusConnection *)%p has weak reference at %p pointing to %p",
+ conn, ref, self);
+ TRACE(self);
+ Py_INCREF(self);
+ TRACE(self);
+ return self;
+ }
+ }
+
+ PyErr_SetString(PyExc_AssertionError,
+ "D-Bus connection does not have a Connection "
+ "instance associated with it");
+ return NULL;
+}
+
+/* Return a new reference to a Python Connection or subclass (given by cls)
+ * corresponding to the DBusConnection conn, which must have been newly
+ * created. For use by the Connection and Bus constructors.
+ *
+ * Raises AssertionError if the DBusConnection already has a Connection.
+ */
+static PyObject *
+DBusPyConnection_NewConsumingDBusConnection(PyTypeObject *cls,
+ DBusConnection *conn,
+ PyObject *mainloop)
+{
+ Connection *self = NULL;
+ PyObject *ref;
+ dbus_bool_t ok;
+
+ DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__, cls, conn, mainloop);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn);
+
+ Py_BEGIN_ALLOW_THREADS
+ ref = (PyObject *)dbus_connection_get_data(conn,
+ _connection_python_slot);
+ Py_END_ALLOW_THREADS
+ if (ref) {
+ self = (Connection *)PyWeakref_GetObject(ref);
+ ref = NULL;
+ if (self && (PyObject *)self != Py_None) {
+ self = NULL;
+ PyErr_SetString(PyExc_AssertionError,
+ "Newly created D-Bus connection already has a "
+ "Connection instance associated with it");
+ DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__);
+ DBG_WHEREAMI;
+ return NULL;
+ }
+ }
+ ref = NULL;
+
+ /* Change mainloop from a borrowed reference to an owned reference */
+ if (!mainloop || mainloop == Py_None) {
+ mainloop = dbus_py_get_default_main_loop();
+ if (!mainloop)
+ goto err;
+ }
+ else {
+ Py_INCREF(mainloop);
+ }
+
+ DBG("Constructing Connection from DBusConnection at %p", conn);
+
+ self = (Connection *)(cls->tp_alloc(cls, 0));
+ if (!self) goto err;
+ TRACE(self);
+
+ DBG_WHEREAMI;
+
+ self->has_mainloop = (mainloop != Py_None);
+ self->conn = NULL;
+ self->filters = PyList_New(0);
+ self->weaklist = NULL;
+ if (!self->filters) goto err;
+ self->object_paths = PyDict_New();
+ if (!self->object_paths) goto err;
+
+ ref = PyWeakref_NewRef((PyObject *)self, NULL);
+ if (!ref) goto err;
+ DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
+ ref, self, conn);
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_set_data(conn, _connection_python_slot,
+ (void *)ref,
+ (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
+ Py_END_ALLOW_THREADS
+
+ if (ok) {
+ DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
+ ref, self, conn);
+ ref = NULL; /* don't DECREF it - the DBusConnection owns it now */
+ }
+ else {
+ DBG("Failed to attached weak ref %p ((Connection *)%p) to "
+ "(DBusConnection *)%p - will dispose of it", ref, self, conn);
+ PyErr_NoMemory();
+ goto err;
+ }
+
+ DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn, err);
+ self->conn = conn;
+ /* the DBusPyConnection will close it now */
+ conn = NULL;
+
+ if (self->has_mainloop
+ && !dbus_py_set_up_connection((PyObject *)self, mainloop)) {
+ goto err;
+ }
+
+ Py_CLEAR(mainloop);
+
+ DBG("%s() -> %p", __func__, self);
+ TRACE(self);
+ return (PyObject *)self;
+
+err:
+ DBG("Failed to construct Connection from DBusConnection at %p", conn);
+ Py_CLEAR(mainloop);
+ Py_CLEAR(self);
+ Py_CLEAR(ref);
+ if (conn) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ Py_END_ALLOW_THREADS
+ }
+ DBG("%s() fail", __func__);
+ DBG_WHEREAMI;
+ return NULL;
+}
+
+/* Connection type-methods ========================================== */
+
+/* Constructor */
+static PyObject *
+Connection_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ DBusConnection *conn;
+ PyObject *address_or_conn;
+ DBusError error;
+ PyObject *self, *mainloop = NULL;
+ static char *argnames[] = {"address", "mainloop", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", argnames,
+ &address_or_conn, &mainloop)) {
+ return NULL;
+ }
+
+ if (DBusPyLibDBusConnection_CheckExact(address_or_conn)) {
+ DBusPyLibDBusConnection *wrapper =
+ (DBusPyLibDBusConnection *) address_or_conn;
+
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(wrapper->conn);
+
+ conn = dbus_connection_ref (wrapper->conn);
+ }
+ else if (PyBytes_Check(address_or_conn)) {
+ const char *address = PyBytes_AS_STRING(address_or_conn);
+
+ dbus_error_init(&error);
+
+ /* We always open a private connection (at the libdbus level). Sharing
+ * is done in Python, to keep things simple. */
+ Py_BEGIN_ALLOW_THREADS
+ conn = dbus_connection_open_private(address, &error);
+ Py_END_ALLOW_THREADS
+
+ if (!conn) {
+ DBusPyException_ConsumeError(&error);
+ return NULL;
+ }
+ }
+ else if (PyUnicode_Check(address_or_conn)) {
+ PyObject *address_as_bytes = PyUnicode_AsUTF8String(address_or_conn);
+ const char *address;
+
+ if (!address_as_bytes)
+ return NULL;
+ address = PyBytes_AS_STRING(address_as_bytes);
+
+ dbus_error_init(&error);
+
+ /* We always open a private connection (at the libdbus level). Sharing
+ * is done in Python, to keep things simple. */
+ Py_BEGIN_ALLOW_THREADS
+ conn = dbus_connection_open_private(address, &error);
+ Py_END_ALLOW_THREADS
+
+ Py_CLEAR(address_as_bytes);
+ if (!conn) {
+ DBusPyException_ConsumeError(&error);
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "connection or str expected");
+ return NULL;
+ }
+
+ self = DBusPyConnection_NewConsumingDBusConnection(cls, conn, mainloop);
+ TRACE(self);
+
+ return self;
+}
+
+/* Post-construction: nothing to do (but don't chain up to object.__init__,
+ * which takes no arguments and does nothing) */
+static int
+Connection_tp_init(PyObject *self UNUSED, PyObject *args UNUSED,
+ PyObject *kwargs UNUSED)
+{
+ return 0;
+}
+
+/* Destructor */
+static void Connection_tp_dealloc(Connection *self)
+{
+ DBusConnection *conn = self->conn;
+ PyObject *et, *ev, *etb;
+ PyObject *filters = self->filters;
+ PyObject *object_paths = self->object_paths;
+
+ /* avoid clobbering any pending exception */
+ PyErr_Fetch(&et, &ev, &etb);
+
+ if (self->weaklist) {
+ PyObject_ClearWeakRefs((PyObject *)self);
+ }
+
+ TRACE(self);
+ DBG("Deallocating Connection at %p (DBusConnection at %p)", self, conn);
+ DBG_WHEREAMI;
+
+ DBG("Connection at %p: deleting callbacks", self);
+ self->filters = NULL;
+ Py_CLEAR(filters);
+ self->object_paths = NULL;
+ Py_CLEAR(object_paths);
+
+ if (conn) {
+ /* Might trigger callbacks if we're unlucky... */
+ DBG("Connection at %p has a conn, closing it...", self);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_close(conn);
+ Py_END_ALLOW_THREADS
+ }
+
+ /* make sure to do this last to preserve the invariant that
+ * self->conn is always non-NULL for any referenced Connection
+ * (until the filters and object paths were freed, we might have been
+ * in a reference cycle!)
+ */
+ DBG("Connection at %p: nulling self->conn", self);
+ self->conn = NULL;
+
+ if (conn) {
+ DBG("Connection at %p: unreffing conn", self);
+ dbus_connection_unref(conn);
+ }
+
+ DBG("Connection at %p: freeing self", self);
+ PyErr_Restore(et, ev, etb);
+ (Py_TYPE(self)->tp_free)((PyObject *)self);
+}
+
+/* Connection type object =========================================== */
+
+PyTypeObject DBusPyConnection_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_dbus_bindings.Connection", /*tp_name*/
+ sizeof(Connection), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)Connection_tp_dealloc,
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+#ifdef PY3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE,
+#endif
+ Connection_tp_doc, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ offsetof(Connection, weaklist), /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ DBusPyConnection_tp_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ Connection_tp_init, /*tp_init*/
+ 0, /*tp_alloc*/
+ Connection_tp_new, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+};
+
+dbus_bool_t
+dbus_py_init_conn_types(void)
+{
+ /* Get a slot to store our weakref on DBus Connections */
+ _connection_python_slot = -1;
+ if (!dbus_connection_allocate_data_slot(&_connection_python_slot))
+ return FALSE;
+ if (PyType_Ready(&DBusPyConnection_Type) < 0)
+ return FALSE;
+ return TRUE;
+}
+
+dbus_bool_t
+dbus_py_insert_conn_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&DBusPyConnection_Type);
+ if (PyModule_AddObject(this_module, "Connection",
+ (PyObject *)&DBusPyConnection_Type) < 0) return FALSE;
+ return TRUE;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/containers.c b/dbus_bindings/containers.c
new file mode 100644
index 0000000..e364f98
--- /dev/null
+++ b/dbus_bindings/containers.c
@@ -0,0 +1,825 @@
+/* D-Bus container types: Array, Dict and Struct.
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+/* Array ============================================================ */
+
+PyDoc_STRVAR(Array_tp_doc,
+"An array of similar items, implemented as a subtype of list.\n"
+"\n"
+"As currently implemented, an Array behaves just like a list, but\n"
+"with the addition of a ``signature`` property set by the constructor;\n"
+"conversion of its items to D-Bus types is only done when it's sent in\n"
+"a Message. This might change in future so validation is done earlier.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Array([iterable][, signature][, variant_level])\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+"``signature`` is the D-Bus signature string for a single element of the\n"
+"array, or None. If not None it must represent a single complete type, the\n"
+"type of a single array item; the signature of the whole Array may be\n"
+"obtained by prepending ``a`` to the given signature.\n"
+"\n"
+"If None (the default), when the Array is sent over\n"
+"D-Bus, the item signature will be guessed from the first element.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an array, this is represented in Python by an\n"
+" Array with variant_level==2.\n"
+);
+
+static struct PyMemberDef Array_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(DBusPyArray, signature), READONLY,
+ "The D-Bus signature of each element of this Array (a Signature "
+ "instance)"},
+ {"variant_level", T_LONG, offsetof(DBusPyArray, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static void
+Array_tp_dealloc (DBusPyArray *self)
+{
+ Py_CLEAR(self->signature);
+ (PyList_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Array_tp_repr(DBusPyArray *self)
+{
+ PyObject *parent_repr = (PyList_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+ long variant_level = self->variant_level;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Array_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *variant_level = NULL;
+ DBusPyArray *self = (DBusPyArray *)(PyList_Type.tp_new)(cls, args, kwargs);
+
+ /* variant_level is immutable, so handle it in __new__ rather than
+ __init__ */
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ self->variant_level = 0;
+ if (kwargs) {
+ variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
+ }
+ if (variant_level) {
+ long new_variant_level = PyLong_AsLong(variant_level);
+ if (new_variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ self->variant_level = new_variant_level;
+ }
+ return (PyObject *)self;
+}
+
+static int
+Array_tp_init (DBusPyArray *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = dbus_py_empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ PyObject *variant_level;
+ /* variant_level is accepted but ignored - it's immutable, so
+ * __new__ handles it */
+ static char *argnames[] = {"iterable", "signature", "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
+ &obj, &signature, &variant_level)) {
+ return -1;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) return -1;
+ }
+
+ if (signature != Py_None) {
+ const char *c_str;
+ PyObject *signature_as_bytes;
+
+ if (
+#ifdef PY3
+ !PyUnicode_Check(signature)
+#else
+ !PyBytes_Check(signature)
+#endif
+ )
+ {
+ PyErr_SetString(PyExc_TypeError, "str expected");
+ Py_CLEAR(signature);
+ return -1;
+ }
+#ifdef PY3
+ if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+#else
+ signature_as_bytes = signature;
+ Py_INCREF(signature_as_bytes);
+#endif
+
+ c_str = PyBytes_AS_STRING(signature_as_bytes);
+
+ if (!dbus_signature_validate_single(c_str, NULL)) {
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "There must be exactly one complete type in "
+ "an Array's signature parameter");
+ return -1;
+ }
+ Py_CLEAR(signature_as_bytes);
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+ if ((PyList_Type.tp_init)((PyObject *)self, tuple, NULL) < 0) {
+ Py_CLEAR(tuple);
+ Py_CLEAR(signature);
+ return -1;
+ }
+ Py_CLEAR(tuple);
+
+ Py_CLEAR(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+PyTypeObject DBusPyArray_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Array",
+ sizeof(DBusPyArray),
+ 0,
+ (destructor)Array_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Array_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Array_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ Array_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Array_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ Array_tp_new, /* tp_new */
+};
+
+/* Dict ============================================================= */
+
+PyDoc_STRVAR(Dict_tp_doc,
+"An mapping whose keys are similar and whose values are similar,\n"
+"implemented as a subtype of dict.\n"
+"\n"
+"As currently implemented, a Dictionary behaves just like a dict, but\n"
+"with the addition of a ``signature`` property set by the constructor;\n"
+"conversion of its items to D-Bus types is only done when it's sent in\n"
+"a Message. This may change in future so validation is done earlier.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+"``signature`` is either a string or None. If a string, it must consist\n"
+"of exactly two complete type signatures, representing the 'key' type\n"
+"(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n"
+"and the 'value' type. The signature of the whole Dictionary will be\n"
+"``a{xx}`` where ``xx`` is replaced by the given signature.\n"
+"\n"
+"If it is None (the default), when the Dictionary is sent over\n"
+"D-Bus, the key and value signatures will be guessed from an arbitrary\n"
+"element of the Dictionary.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an array of DICT_ENTRY, this is represented in\n"
+" Python by a Dictionary with variant_level==2.\n"
+);
+
+static struct PyMemberDef Dict_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(DBusPyDict, signature), READONLY,
+ "The D-Bus signature of each key in this Dictionary, followed by "
+ "that of each value in this Dictionary, as a Signature instance."},
+ {"variant_level", T_LONG, offsetof(DBusPyDict, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static void
+Dict_tp_dealloc (DBusPyDict *self)
+{
+ Py_CLEAR(self->signature);
+ (PyDict_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Dict_tp_repr(DBusPyDict *self)
+{
+ PyObject *parent_repr = (PyDict_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+ long variant_level = self->variant_level;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Dict_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ DBusPyDict *self = (DBusPyDict *)(PyDict_Type.tp_new)(cls, args, kwargs);
+ PyObject *variant_level = NULL;
+
+ /* variant_level is immutable, so handle it in __new__ rather than
+ __init__ */
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ self->variant_level = 0;
+ if (kwargs) {
+ variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
+ }
+ if (variant_level) {
+ long new_variant_level = PyLong_AsLong(variant_level);
+
+ if (new_variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ self->variant_level = new_variant_level;
+ }
+ return (PyObject *)self;
+}
+
+static int
+Dict_tp_init(DBusPyDict *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = dbus_py_empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ PyObject *variant_level; /* ignored here - __new__ uses it */
+ static char *argnames[] = {"mapping_or_iterable", "signature",
+ "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
+ &obj, &signature, &variant_level)) {
+ return -1;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) return -1;
+ }
+
+ if (signature != Py_None) {
+ const char *c_str;
+ PyObject *signature_as_bytes;
+
+ if (!NATIVESTR_CHECK(signature)) {
+ PyErr_SetString(PyExc_TypeError, "str expected");
+ Py_CLEAR(signature);
+ return -1;
+ }
+#ifdef PY3
+ if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+#else
+ signature_as_bytes = signature;
+ Py_INCREF(signature_as_bytes);
+#endif
+
+ c_str = PyBytes_AS_STRING(signature_as_bytes);
+ switch (c_str[0]) {
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_DOUBLE:
+#ifdef WITH_DBUS_FLOAT32
+ case DBUS_TYPE_FLOAT:
+#endif
+#ifdef DBUS_TYPE_UNIX_FD
+ case DBUS_TYPE_UNIX_FD:
+#endif
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ break;
+ default:
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "The key type in a Dictionary's signature "
+ "must be a primitive type");
+ return -1;
+ }
+
+ if (!dbus_signature_validate_single(c_str + 1, NULL)) {
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "There must be exactly two complete types in "
+ "a Dictionary's signature parameter");
+ return -1;
+ }
+ Py_CLEAR(signature_as_bytes);
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+
+ if ((PyDict_Type.tp_init((PyObject *)self, tuple, NULL)) < 0) {
+ Py_CLEAR(tuple);
+ Py_CLEAR(signature);
+ return -1;
+ }
+ Py_CLEAR(tuple);
+
+ Py_CLEAR(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+PyTypeObject DBusPyDict_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Dictionary",
+ sizeof(DBusPyDict),
+ 0,
+ (destructor)Dict_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Dict_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Dict_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ Dict_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Dict_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ Dict_tp_new, /* tp_new */
+};
+
+/* Struct =========================================================== */
+
+static PyObject *struct_signatures;
+
+PyDoc_STRVAR(Struct_tp_doc,
+"An structure containing items of possibly distinct types.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
+"\n"
+"D-Bus structs may not be empty, so the iterable argument is required and\n"
+"may not be an empty iterable.\n"
+"\n"
+"``signature`` is either None, or a string representing the contents of the\n"
+"struct as one or more complete type signatures. The overall signature of\n"
+"the struct will be the given signature enclosed in parentheses, ``()``.\n"
+"\n"
+"If the signature is None (default) it will be guessed\n"
+"from the types of the items during construction.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a struct, this is represented in Python by a\n"
+" Struct with variant_level==2.\n"
+);
+
+static PyObject *
+Struct_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyTuple_Type.tp_repr)((PyObject *)self);
+ PyObject *sig;
+ PyObject *sig_repr = NULL;
+ PyObject *key;
+ long variant_level;
+ PyObject *my_repr = NULL;
+
+ if (!parent_repr) goto finally;
+ key = PyLong_FromVoidPtr(self);
+ if (!key) goto finally;
+ sig = PyDict_GetItem(struct_signatures, key);
+ Py_CLEAR(key);
+ if (!sig) sig = Py_None;
+ sig_repr = PyObject_Repr(sig);
+ if (!sig_repr) goto finally;
+
+ variant_level = dbus_py_variant_level_get(self);
+ if (variant_level < 0)
+ goto finally;
+
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *signature = NULL;
+ long variantness = 0;
+ PyObject *self, *key;
+ static char *argnames[] = {"signature", "variant_level", NULL};
+
+ if (PyTuple_Size(args) != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes exactly one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|Ol:__new__", argnames,
+ &signature, &variantness)) {
+ return NULL;
+ }
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyTuple_Type.tp_new)(cls, args, NULL);
+ if (!self)
+ return NULL;
+ if (PyTuple_Size(self) < 1) {
+ PyErr_SetString(PyExc_ValueError, "D-Bus structs may not be empty");
+ Py_CLEAR(self);
+ return NULL;
+ }
+
+ if (!dbus_py_variant_level_set(self, variantness)) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ }
+
+ key = PyLong_FromVoidPtr(self);
+ if (!key) {
+ Py_CLEAR(self);
+ Py_CLEAR(signature);
+ return NULL;
+ }
+ if (PyDict_SetItem(struct_signatures, key, signature) < 0) {
+ Py_CLEAR(key);
+ Py_CLEAR(self);
+ Py_CLEAR(signature);
+ return NULL;
+ }
+
+ Py_CLEAR(key);
+ Py_CLEAR(signature);
+ return self;
+}
+
+static void
+Struct_tp_dealloc(PyObject *self)
+{
+ PyObject *et, *ev, *etb, *key;
+
+ dbus_py_variant_level_clear(self);
+ PyErr_Fetch(&et, &ev, &etb);
+
+ key = PyLong_FromVoidPtr(self);
+ if (key) {
+ if (PyDict_GetItem(struct_signatures, key)) {
+ if (PyDict_DelItem(struct_signatures, key) < 0) {
+ /* should never happen */
+ PyErr_WriteUnraisable(self);
+ }
+ }
+ Py_CLEAR(key);
+ }
+ else {
+ /* not enough memory to free all the memory... leak the signature,
+ * there's not much else we could do here */
+ PyErr_WriteUnraisable(self);
+ }
+
+ PyErr_Restore(et, ev, etb);
+ (PyTuple_Type.tp_dealloc)(self);
+}
+
+static PyObject *
+Struct_tp_getattro(PyObject *obj, PyObject *name)
+{
+ PyObject *key, *value;
+
+#ifdef PY3
+ if (PyUnicode_CompareWithASCIIString(name, "signature"))
+ return dbus_py_variant_level_getattro(obj, name);
+#else
+ if (PyBytes_Check(name)) {
+ Py_INCREF(name);
+ }
+ else if (PyUnicode_Check(name)) {
+ name = PyUnicode_AsEncodedString(name, NULL, NULL);
+ if (!name) {
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "attribute name must be string");
+ return NULL;
+ }
+
+ if (strcmp(PyBytes_AS_STRING(name), "signature")) {
+ value = dbus_py_variant_level_getattro(obj, name);
+ Py_CLEAR(name);
+ return value;
+ }
+ Py_CLEAR(name);
+#endif /* PY3 */
+
+ key = PyLong_FromVoidPtr(obj);
+
+ if (!key) {
+ return NULL;
+ }
+
+ value = PyDict_GetItem(struct_signatures, key);
+ Py_CLEAR(key);
+
+ if (!value)
+ value = Py_None;
+ Py_INCREF(value);
+ return value;
+}
+
+PyTypeObject DBusPyStruct_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Struct",
+ 0,
+ 0,
+ Struct_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Struct_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ Struct_tp_getattro, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Struct_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Struct_tp_new, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_container_types(void)
+{
+ struct_signatures = PyDict_New();
+ if (!struct_signatures) return 0;
+
+ DBusPyArray_Type.tp_base = &PyList_Type;
+ if (PyType_Ready(&DBusPyArray_Type) < 0) return 0;
+ DBusPyArray_Type.tp_print = NULL;
+
+ DBusPyDict_Type.tp_base = &PyDict_Type;
+ if (PyType_Ready(&DBusPyDict_Type) < 0) return 0;
+ DBusPyDict_Type.tp_print = NULL;
+
+ DBusPyStruct_Type.tp_base = &PyTuple_Type;
+ if (PyType_Ready(&DBusPyStruct_Type) < 0) return 0;
+ DBusPyStruct_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_container_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyArray_Type);
+ if (PyModule_AddObject(this_module, "Array",
+ (PyObject *)&DBusPyArray_Type) < 0) return 0;
+
+ Py_INCREF(&DBusPyDict_Type);
+ if (PyModule_AddObject(this_module, "Dictionary",
+ (PyObject *)&DBusPyDict_Type) < 0) return 0;
+
+ Py_INCREF(&DBusPyStruct_Type);
+ if (PyModule_AddObject(this_module, "Struct",
+ (PyObject *)&DBusPyStruct_Type) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
+
diff --git a/dbus_bindings/dbus_bindings-internal.h b/dbus_bindings/dbus_bindings-internal.h
new file mode 100644
index 0000000..b3006b5
--- /dev/null
+++ b/dbus_bindings/dbus_bindings-internal.h
@@ -0,0 +1,296 @@
+/* _dbus_bindings internal API. For use within _dbus_bindings only.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBUS_BINDINGS_INTERNAL_H
+#define DBUS_BINDINGS_INTERNAL_H
+
+#define PY_SSIZE_T_CLEAN 1
+#define PY_SIZE_T_CLEAN 1
+
+#include <Python.h>
+
+#define INSIDE_DBUS_PYTHON_BINDINGS
+#include "dbus/dbus-python.h"
+
+#if defined(__GNUC__)
+# if __GNUC__ >= 3
+# define UNUSED __attribute__((__unused__))
+# define NORETURN __attribute__((__noreturn__))
+# else
+# define UNUSED /*nothing*/
+# define NORETURN /*nothing*/
+# endif
+#else
+# define UNUSED /*nothing*/
+# define NORETURN /*nothing*/
+#endif
+
+/* no need for extern "C", this is only for internal use */
+
+/* on/off switch for debugging support (see below) */
+#undef USING_DBG
+#if 0 && !defined(DBG_IS_TOO_VERBOSE)
+# define USING_DBG 1
+#endif
+
+#define DEFINE_CHECK(type) \
+static inline int type##_Check (PyObject *o) \
+{ \
+ return (PyObject_TypeCheck (o, &type##_Type)); \
+} \
+static inline int type##_CheckExact (PyObject *o) \
+{ \
+ return (Py_TYPE(o) == &type##_Type); \
+}
+
+/* This is a clever little trick to make writing the various object reprs
+ * easier. It relies on Python's %V format option which consumes two
+ * arguments. The first is a unicode object which may be NULL, and the second
+ * is a char* which will be used if the first parameter is NULL.
+ *
+ * The issue is that we don't know whether the `parent_repr` at the call site
+ * is a unicode or a bytes (a.k.a. 8-bit string). Under Python 3, it will
+ * always be a unicode. Under Python 2 it will *probably* be a bytes/str, but
+ * could potentially be a unicode. So, we check the type, and if it's a
+ * unicode, we pass that as the first argument, leaving NULL as the second
+ * argument (since it will never be checked). However, if the object is not a
+ * unicode, it better be a bytes. In that case, we'll pass NULL as the first
+ * argument so that the second one gets used, and we'll dig the char* out of
+ * the bytes object for that purpose.
+ *
+ * You might think that this would crash if obj is neither a bytes/str or
+ * unicode, and you'd be right *except* that Python doesn't allow any other
+ * types to be returned in the reprs. Also, since obj will always be the repr
+ * of a built-in type, it will never be anything other than a bytes or a
+ * unicode in any version of Python. So in practice, this is safe.
+ */
+#define REPRV(obj) \
+ (PyUnicode_Check(obj) ? (obj) : NULL), \
+ (PyUnicode_Check(obj) ? NULL : PyBytes_AS_STRING(obj))
+
+#ifdef PY3
+#define NATIVEINT_TYPE (PyLong_Type)
+#define NATIVEINT_FROMLONG(x) (PyLong_FromLong(x))
+#define NATIVEINT_ASLONG(x) (PyLong_AsLong(x))
+#define INTORLONG_CHECK(obj) (PyLong_Check(obj))
+#define NATIVESTR_TYPE (PyUnicode_Type)
+#define NATIVESTR_CHECK(obj) (PyUnicode_Check(obj))
+#define NATIVESTR_FROMSTR(obj) (PyUnicode_FromString(obj))
+#else
+#define NATIVEINT_TYPE (PyInt_Type)
+#define NATIVEINT_FROMLONG(x) (PyInt_FromLong(x))
+#define NATIVEINT_ASLONG(x) (PyInt_AsLong(x))
+#define INTORLONG_CHECK(obj) (PyLong_Check(obj) || PyInt_Check(obj))
+#define NATIVESTR_TYPE (PyBytes_Type)
+#define NATIVESTR_CHECK(obj) (PyBytes_Check(obj))
+#define NATIVESTR_FROMSTR(obj) (PyBytes_FromString(obj))
+#endif
+
+#ifdef PY3
+PyMODINIT_FUNC PyInit__dbus_bindings(void);
+#else
+PyMODINIT_FUNC init_dbus_bindings(void);
+#endif
+
+/* conn.c */
+extern PyTypeObject DBusPyConnection_Type;
+DEFINE_CHECK(DBusPyConnection)
+extern dbus_bool_t dbus_py_init_conn_types(void);
+extern dbus_bool_t dbus_py_insert_conn_types(PyObject *this_module);
+
+/* libdbusconn.c */
+extern PyTypeObject DBusPyLibDBusConnection_Type;
+DEFINE_CHECK(DBusPyLibDBusConnection)
+PyObject *DBusPyLibDBusConnection_New(DBusConnection *conn);
+extern dbus_bool_t dbus_py_init_libdbus_conn_types(void);
+extern dbus_bool_t dbus_py_insert_libdbus_conn_types(PyObject *this_module);
+
+/* bus.c */
+extern dbus_bool_t dbus_py_init_bus_types(void);
+extern dbus_bool_t dbus_py_insert_bus_types(PyObject *this_module);
+
+/* exceptions.c */
+extern PyObject *DBusPyException_SetString(const char *msg);
+extern PyObject *DBusPyException_ConsumeError(DBusError *error);
+extern dbus_bool_t dbus_py_init_exception_types(void);
+extern dbus_bool_t dbus_py_insert_exception_types(PyObject *this_module);
+
+/* types */
+extern PyTypeObject DBusPyBoolean_Type;
+DEFINE_CHECK(DBusPyBoolean)
+extern PyTypeObject DBusPyObjectPath_Type, DBusPySignature_Type;
+DEFINE_CHECK(DBusPyObjectPath)
+DEFINE_CHECK(DBusPySignature)
+extern PyTypeObject DBusPyArray_Type, DBusPyDict_Type, DBusPyStruct_Type;
+DEFINE_CHECK(DBusPyArray)
+DEFINE_CHECK(DBusPyDict)
+DEFINE_CHECK(DBusPyStruct)
+extern PyTypeObject DBusPyByte_Type, DBusPyByteArray_Type;
+DEFINE_CHECK(DBusPyByteArray)
+DEFINE_CHECK(DBusPyByte)
+extern PyTypeObject DBusPyString_Type;
+DEFINE_CHECK(DBusPyString)
+#ifndef PY3
+extern PyTypeObject DBusPyUTF8String_Type;
+DEFINE_CHECK(DBusPyUTF8String)
+#endif
+extern PyTypeObject DBusPyDouble_Type;
+DEFINE_CHECK(DBusPyDouble)
+extern PyTypeObject DBusPyInt16_Type, DBusPyUInt16_Type;
+DEFINE_CHECK(DBusPyInt16)
+DEFINE_CHECK(DBusPyUInt16)
+extern PyTypeObject DBusPyInt32_Type, DBusPyUInt32_Type;
+DEFINE_CHECK(DBusPyInt32)
+DEFINE_CHECK(DBusPyUInt32)
+extern PyTypeObject DBusPyUnixFd_Type;
+DEFINE_CHECK(DBusPyUnixFd)
+extern PyTypeObject DBusPyInt64_Type, DBusPyUInt64_Type;
+DEFINE_CHECK(DBusPyInt64)
+DEFINE_CHECK(DBusPyUInt64)
+extern dbus_bool_t dbus_py_init_abstract(void);
+extern dbus_bool_t dbus_py_init_signature(void);
+extern dbus_bool_t dbus_py_init_int_types(void);
+extern dbus_bool_t dbus_py_init_unixfd_type(void);
+extern dbus_bool_t dbus_py_init_string_types(void);
+extern dbus_bool_t dbus_py_init_float_types(void);
+extern dbus_bool_t dbus_py_init_container_types(void);
+extern dbus_bool_t dbus_py_init_byte_types(void);
+extern dbus_bool_t dbus_py_insert_abstract_types(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_signature(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_int_types(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_unixfd_type(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_string_types(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_float_types(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_container_types(PyObject *this_module);
+extern dbus_bool_t dbus_py_insert_byte_types(PyObject *this_module);
+
+int dbus_py_unix_fd_get_fd(PyObject *self);
+
+/* generic */
+extern void dbus_py_take_gil_and_xdecref(PyObject *);
+extern int dbus_py_immutable_setattro(PyObject *, PyObject *, PyObject *);
+extern PyObject *dbus_py_empty_tuple;
+extern dbus_bool_t dbus_py_init_generic(void);
+
+/* message.c */
+extern DBusMessage *DBusPyMessage_BorrowDBusMessage(PyObject *msg);
+extern PyObject *DBusPyMessage_ConsumeDBusMessage(DBusMessage *);
+extern dbus_bool_t dbus_py_init_message_types(void);
+extern dbus_bool_t dbus_py_insert_message_types(PyObject *this_module);
+
+/* pending-call.c */
+extern PyObject *DBusPyPendingCall_ConsumeDBusPendingCall(DBusPendingCall *,
+ PyObject *);
+extern dbus_bool_t dbus_py_init_pending_call(void);
+extern dbus_bool_t dbus_py_insert_pending_call(PyObject *this_module);
+
+/* mainloop.c */
+extern dbus_bool_t dbus_py_set_up_connection(PyObject *conn,
+ PyObject *mainloop);
+extern dbus_bool_t dbus_py_set_up_server(PyObject *server,
+ PyObject *mainloop);
+extern PyObject *dbus_py_get_default_main_loop(void);
+extern dbus_bool_t dbus_py_check_mainloop_sanity(PyObject *);
+extern dbus_bool_t dbus_py_init_mainloop(void);
+extern dbus_bool_t dbus_py_insert_mainloop_types(PyObject *);
+
+/* server.c */
+extern PyTypeObject DBusPyServer_Type;
+DEFINE_CHECK(DBusPyServer)
+extern dbus_bool_t dbus_py_init_server_types(void);
+extern dbus_bool_t dbus_py_insert_server_types(PyObject *this_module);
+extern DBusServer *DBusPyServer_BorrowDBusServer(PyObject *self);
+
+/* validation.c */
+dbus_bool_t dbus_py_validate_bus_name(const char *name,
+ dbus_bool_t may_be_unique,
+ dbus_bool_t may_be_not_unique);
+dbus_bool_t dbus_py_validate_member_name(const char *name);
+dbus_bool_t dbus_py_validate_interface_name(const char *name);
+dbus_bool_t dbus_py_validate_object_path(const char *path);
+#define dbus_py_validate_error_name dbus_py_validate_interface_name
+
+/* debugging support */
+void _dbus_py_assertion_failed(const char *) NORETURN;
+#define DBUS_PY_RAISE_VIA_NULL_IF_FAIL(assertion) \
+ do { if (!(assertion)) { \
+ _dbus_py_assertion_failed(#assertion); \
+ return NULL; \
+ } \
+ } while (0)
+
+#define DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(assertion, label) \
+ do { if (!(assertion)) { \
+ _dbus_py_assertion_failed(#assertion); \
+ goto label; \
+ } \
+ } while (0)
+
+#define DBUS_PY_RAISE_VIA_RETURN_IF_FAIL(assertion, value) \
+ do { if (!(assertion)) { \
+ _dbus_py_assertion_failed(#assertion); \
+ return value; \
+ } \
+ } while (0)
+
+/* verbose debugging support */
+#ifdef USING_DBG
+
+# include <sys/types.h>
+# include <unistd.h>
+
+void _dbus_py_dbg_exc(void);
+void _dbus_py_whereami(void);
+void _dbus_py_dbg_dump_message(DBusMessage *);
+
+# define TRACE(self) do { \
+ fprintf(stderr, "TRACE: <%s at %p> in %s, " \
+ "%d refs\n", \
+ self ? Py_TYPE(self)->tp_name : NULL, \
+ self, __func__, \
+ self ? (int)Py_REFCNT(self) : 0); \
+ } while (0)
+# define DBG(format, ...) fprintf(stderr, "DEBUG: " format "\n",\
+ __VA_ARGS__)
+# define DBG_EXC(format, ...) do {DBG(format, __VA_ARGS__); \
+ _dbus_py_dbg_exc();} while (0)
+# define DBG_DUMP_MESSAGE(x) _dbus_py_dbg_dump_message(x)
+# define DBG_WHEREAMI _dbus_py_whereami()
+
+#else /* !defined(USING_DBG) */
+
+# define TRACE(self) do {} while (0)
+# define DBG(format, ...) do {} while (0)
+# define DBG_EXC(format, ...) do {} while (0)
+# define DBG_DUMP_MESSAGE(x) do {} while (0)
+# define DBG_WHEREAMI do {} while (0)
+
+#endif /* !defined(USING_DBG) */
+
+/* General-purpose Python glue */
+
+#define DEFERRED_ADDRESS(ADDR) 0
+
+#endif
diff --git a/dbus_bindings/debug.c b/dbus_bindings/debug.c
new file mode 100644
index 0000000..4620c86
--- /dev/null
+++ b/dbus_bindings/debug.c
@@ -0,0 +1,96 @@
+/* Debug code for _dbus_bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <stdlib.h>
+
+void
+_dbus_py_assertion_failed(const char *assertion)
+{
+ PyErr_SetString(PyExc_AssertionError, assertion);
+#if 1 || defined(USING_DBG) || defined(FATAL_ASSERTIONS)
+ /* print the Python stack, and dump core so we can see the C stack too */
+ PyErr_Print();
+ abort();
+#endif
+}
+
+#ifdef USING_DBG
+void
+_dbus_py_whereami(void)
+{
+ PyObject *c, *v, *t;
+ /* This is a little mad. We want to get the traceback without
+ clearing the error indicator, if any. */
+ PyErr_Fetch(&c, &v, &t); /* 3 new refs */
+ Py_XINCREF(c); Py_XINCREF(v); Py_XINCREF(t); /* now we own 6 refs */
+ PyErr_Restore(c, v, t); /* steals 3 refs */
+
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_AssertionError,
+ "No error, but plz provide traceback kthx");
+ }
+ PyErr_Print();
+
+ PyErr_Restore(c, v, t); /* steals another 3 refs */
+}
+
+void
+_dbus_py_dbg_exc(void)
+{
+ PyObject *c, *v, *t;
+ /* This is a little mad. We want to get the traceback without
+ clearing the error indicator. */
+ PyErr_Fetch(&c, &v, &t); /* 3 new refs */
+ Py_XINCREF(c); Py_XINCREF(v); Py_XINCREF(t); /* now we own 6 refs */
+ PyErr_Restore(c, v, t); /* steals 3 refs */
+ PyErr_Print();
+ PyErr_Restore(c, v, t); /* steals another 3 refs */
+}
+
+void
+_dbus_py_dbg_dump_message(DBusMessage *message)
+{
+ const char *s;
+ fprintf(stderr, "DBusMessage at %p\n", message);
+
+ s = dbus_message_get_destination(message);
+ if (!s) s = "(null)";
+ fprintf(stderr, "\tdestination %s\n", s);
+
+ s = dbus_message_get_interface(message);
+ if (!s) s = "(null)";
+ fprintf(stderr, "\tinterface %s\n", s);
+
+ s = dbus_message_get_member(message);
+ if (!s) s = "(null)";
+ fprintf(stderr, "\tmember %s\n", s);
+
+ s = dbus_message_get_path(message);
+ if (!s) s = "(null)";
+ fprintf(stderr, "\tpath %s\n", s);
+}
+#endif
diff --git a/dbus_bindings/exceptions.c b/dbus_bindings/exceptions.c
new file mode 100644
index 0000000..6721f5c
--- /dev/null
+++ b/dbus_bindings/exceptions.c
@@ -0,0 +1,104 @@
+/* D-Bus exception base classes.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+static PyObject *imported_dbus_exception = NULL;
+
+static dbus_bool_t
+import_exception(void)
+{
+ PyObject *name;
+ PyObject *exceptions;
+
+ if (imported_dbus_exception != NULL) {
+ return TRUE;
+ }
+
+ name = NATIVESTR_FROMSTR("dbus.exceptions");
+ if (name == NULL) {
+ return FALSE;
+ }
+ exceptions = PyImport_Import(name);
+ Py_CLEAR(name);
+ if (exceptions == NULL) {
+ return FALSE;
+ }
+ imported_dbus_exception = PyObject_GetAttrString(exceptions,
+ "DBusException");
+ Py_CLEAR(exceptions);
+
+ return (imported_dbus_exception != NULL);
+}
+
+PyObject *
+DBusPyException_SetString(const char *msg)
+{
+ if (imported_dbus_exception != NULL || import_exception()) {
+ PyErr_SetString(imported_dbus_exception, msg);
+ }
+ return NULL;
+}
+
+PyObject *
+DBusPyException_ConsumeError(DBusError *error)
+{
+ PyObject *exc_value = NULL;
+
+ if (imported_dbus_exception == NULL && !import_exception()) {
+ goto finally;
+ }
+
+ exc_value = PyObject_CallFunction(imported_dbus_exception,
+ "s",
+ error->message ? error->message
+ : "");
+
+ if (!exc_value) {
+ goto finally;
+ }
+
+ if (error->name) {
+ PyObject *name = NATIVESTR_FROMSTR(error->name);
+ int ret;
+
+ if (!name)
+ goto finally;
+ ret = PyObject_SetAttrString(exc_value, "_dbus_error_name", name);
+ Py_CLEAR(name);
+ if (ret < 0) {
+ goto finally;
+ }
+ }
+
+ PyErr_SetObject(imported_dbus_exception, exc_value);
+
+finally:
+ Py_CLEAR(exc_value);
+ dbus_error_free(error);
+ return NULL;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/float.c b/dbus_bindings/float.c
new file mode 100644
index 0000000..9d05c19
--- /dev/null
+++ b/dbus_bindings/float.c
@@ -0,0 +1,156 @@
+/* Simple D-Bus types: Double and (with appropriate #defines) Float
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+PyDoc_STRVAR(Double_tp_doc,
+"A double-precision floating point number (a subtype of float).");
+
+#ifdef WITH_DBUS_FLOAT32
+PyDoc_STRVAR(Float_tp_doc,
+"A single-precision floating point number (a subtype of float).");
+#endif
+
+PyTypeObject DBusPyDouble_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Double",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Double_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPythonFloatType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+#ifdef WITH_DBUS_FLOAT32
+
+PyTypeObject DBusPyFloat_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Float",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Float_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPythonFloatType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+#endif /* defined(WITH_DBUS_FLOAT32) */
+
+dbus_bool_t
+dbus_py_init_float_types(void)
+{
+ DBusPyDouble_Type.tp_base = &DBusPyFloatBase_Type;
+ if (PyType_Ready(&DBusPyDouble_Type) < 0) return 0;
+ DBusPyDouble_Type.tp_print = NULL;
+
+#ifdef WITH_DBUS_FLOAT32
+ DBusPyFloat_Type.tp_base = &DBusPyFloatBase_Type;
+ if (PyType_Ready(&DBusPyFloat_Type) < 0) return 0;
+ DBusPyFloat_Type.tp_print = NULL;
+#endif
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_float_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyDouble_Type);
+ if (PyModule_AddObject(this_module, "Double",
+ (PyObject *)&DBusPyDouble_Type) < 0) return 0;
+#ifdef WITH_DBUS_FLOAT32
+ Py_INCREF(&DBusPyFloat_Type);
+ if (PyModule_AddObject(this_module, "Float",
+ (PyObject *)&DBusPyFloat_Type) < 0) return 0;
+#endif
+
+ return 1;
+}
diff --git a/dbus_bindings/generic.c b/dbus_bindings/generic.c
new file mode 100644
index 0000000..ed12025
--- /dev/null
+++ b/dbus_bindings/generic.c
@@ -0,0 +1,61 @@
+/* General Python glue code, used in _dbus_bindings but not actually anything
+ * to do with D-Bus.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+/* The empty tuple, held globally since dbus-python turns out to use it quite
+ * a lot
+ */
+PyObject *dbus_py_empty_tuple = NULL;
+
+int
+dbus_py_immutable_setattro(PyObject *obj UNUSED,
+ PyObject *name UNUSED,
+ PyObject *value UNUSED)
+{
+ PyErr_SetString(PyExc_AttributeError, "Object is immutable");
+ return -1;
+}
+
+/* Take the global interpreter lock and decrement the reference count.
+ * Suitable for calling from a C callback. */
+void
+dbus_py_take_gil_and_xdecref(PyObject *obj)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ Py_CLEAR(obj);
+ PyGILState_Release(gil);
+}
+
+dbus_bool_t
+dbus_py_init_generic(void)
+{
+ dbus_py_empty_tuple = PyTuple_New(0);
+ if (!dbus_py_empty_tuple) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/int.c b/dbus_bindings/int.c
new file mode 100644
index 0000000..66ad9e0
--- /dev/null
+++ b/dbus_bindings/int.c
@@ -0,0 +1,804 @@
+/* Simple D-Bus types: integers of various sizes, and ObjectPath.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "types-internal.h"
+
+#ifdef PY3
+#define INTBASE (DBusPyLongBase_Type)
+#else
+#define INTBASE (DBusPyIntBase_Type)
+#endif
+
+/* Specific types =================================================== */
+
+/* Boolean, a subclass of DBusPythonInt ============================= */
+
+PyDoc_STRVAR(Boolean_tp_doc,
+"A boolean, represented as a subtype of `int` (not `bool`, because `bool`\n"
+"cannot be subclassed).\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Boolean(value[, variant_level]) -> Boolean\n"
+"\n"
+"``value`` is converted to 0 or 1 as if by ``int(bool(value))``.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a boolean, this is represented in Python by a\n"
+" Boolean with variant_level==2.\n"
+);
+
+static PyObject *
+Boolean_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *tuple, *self, *value = Py_None;
+ long variantness = 0;
+ static char *argnames[] = {"_", "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Ol:__new__", argnames,
+ &value, &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+ tuple = Py_BuildValue("(i)", PyObject_IsTrue(value) ? 1 : 0);
+ if (!tuple) return NULL;
+ self = (INTBASE.tp_new)(cls, tuple, kwargs);
+ Py_CLEAR(tuple);
+ return self;
+}
+
+static PyObject *
+Boolean_tp_repr(PyObject *self)
+{
+ int is_true = PyObject_IsTrue(self);
+#ifdef PY3
+ long variant_level = dbus_py_variant_level_get(self);
+ if (variant_level < 0)
+ return NULL;
+#else
+ long variant_level = ((DBusPyIntBase *)self)->variant_level;
+#endif
+
+ if (is_true == -1)
+ return NULL;
+
+ if (variant_level > 0) {
+ return PyUnicode_FromFormat("%s(%s, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ is_true ? "True" : "False",
+ variant_level);
+ }
+ return PyUnicode_FromFormat("%s(%s)",
+ Py_TYPE(self)->tp_name,
+ is_true ? "True" : "False");
+}
+
+PyTypeObject DBusPyBoolean_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Boolean",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ Boolean_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Boolean_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&INTBASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Boolean_tp_new, /* tp_new */
+};
+
+/* Int16 ============================================================ */
+
+PyDoc_STRVAR(Int16_tp_doc,
+"A signed 16-bit integer between -0x8000 and +0x7FFF, represented as\n"
+"a subtype of `int`.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Int16(value: int[, variant_level: int]) -> Int16\n"
+"\n"
+"value must be within the allowed range, or OverflowError will be\n"
+"raised.\n"
+"\n"
+" variant_level must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an int16, this is represented in Python by an\n"
+" Int16 with variant_level==2.\n"
+);
+
+dbus_int16_t
+dbus_py_int16_range_check(PyObject *obj)
+{
+ long i = PyLong_AsLong(obj);
+ if (i == -1 && PyErr_Occurred())
+ return -1;
+
+ if (i < -0x8000 || i > 0x7fff) {
+ PyErr_Format(PyExc_OverflowError, "Value %d out of range for Int16",
+ (int)i);
+ return -1;
+ }
+ return (dbus_int16_t)i;
+}
+
+static PyObject *
+Int16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (INTBASE.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_int16_range_check(self) == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ return self;
+}
+
+PyTypeObject DBusPyInt16_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Int16",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Int16_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&INTBASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Int16_tp_new, /* tp_new */
+};
+
+/* UInt16 =========================================================== */
+
+PyDoc_STRVAR(UInt16_tp_doc,
+"An unsigned 16-bit integer between 0 and 0xFFFF, represented as\n"
+"a subtype of `int`.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.UInt16(value: int[, variant_level: int]) -> UInt16\n"
+"\n"
+"``value`` must be within the allowed range, or `OverflowError` will be\n"
+"raised.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a uint16, this is represented in Python by a\n"
+" UInt16 with variant_level==2.\n"
+);
+
+dbus_uint16_t
+dbus_py_uint16_range_check(PyObject *obj)
+{
+ long i = PyLong_AsLong(obj);
+ if (i == -1 && PyErr_Occurred())
+ return (dbus_uint16_t)(-1);
+
+ if (i < 0 || i > 0xffff) {
+ PyErr_Format(PyExc_OverflowError, "Value %d out of range for UInt16",
+ (int)i);
+ return (dbus_uint16_t)(-1);
+ }
+ return (dbus_uint16_t)i;
+}
+
+static PyObject *
+UInt16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (INTBASE.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_uint16_range_check(self) == (dbus_uint16_t)(-1)
+ && PyErr_Occurred())
+ {
+ Py_CLEAR (self);
+ return NULL;
+ }
+ return self;
+}
+
+PyTypeObject DBusPyUInt16_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.UInt16",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UInt16_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&INTBASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ UInt16_tp_new, /* tp_new */
+};
+
+/* Int32 ============================================================ */
+
+PyDoc_STRVAR(Int32_tp_doc,
+"A signed 32-bit integer between -0x8000 0000 and +0x7FFF FFFF, represented as\n"
+"a subtype of `int`.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Int32(value: int[, variant_level: int]) -> Int32\n"
+"\n"
+"``value`` must be within the allowed range, or `OverflowError` will be\n"
+"raised.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an int32, this is represented in Python by an\n"
+" Int32 with variant_level==2.\n"
+);
+
+dbus_int32_t
+dbus_py_int32_range_check(PyObject *obj)
+{
+ long i = PyLong_AsLong(obj);
+ if (i == -1 && PyErr_Occurred())
+ return -1;
+
+ if (i < INT32_MIN || i > INT32_MAX) {
+ PyErr_Format(PyExc_OverflowError, "Value %d out of range for Int32",
+ (int)i);
+ return -1;
+ }
+ return (dbus_int32_t)i;
+}
+
+static PyObject *
+Int32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (INTBASE.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_int32_range_check(self) == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ return self;
+}
+
+PyTypeObject DBusPyInt32_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Int32",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Int32_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&INTBASE), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Int32_tp_new, /* tp_new */
+};
+
+/* UInt32 =========================================================== */
+
+PyDoc_STRVAR(UInt32_tp_doc,
+"An unsigned 32-bit integer between 0 and 0xFFFF FFFF, represented as a\n"
+"subtype of `long`.\n"
+"\n"
+"Note that this may be changed in future to be a subtype of `int` on\n"
+"64-bit platforms; applications should not rely on either behaviour.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.UInt32(value: long[, variant_level: int]) -> UInt32\n"
+"\n"
+"``value`` must be within the allowed range, or `OverflowError` will be\n"
+"raised.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a uint32, this is represented in Python by a\n"
+" UInt32 with variant_level==2.\n"
+);
+
+dbus_uint32_t
+dbus_py_uint32_range_check(PyObject *obj)
+{
+ unsigned long i;
+ PyObject *long_obj = PyNumber_Long(obj);
+
+ if (!long_obj) return (dbus_uint32_t)(-1);
+ i = PyLong_AsUnsignedLong(long_obj);
+ if (i == (unsigned long)(-1) && PyErr_Occurred()) {
+ Py_CLEAR(long_obj);
+ return (dbus_uint32_t)(-1);
+ }
+ if (i > UINT32_MAX) {
+ PyErr_Format(PyExc_OverflowError, "Value %d out of range for UInt32",
+ (int)i);
+ Py_CLEAR(long_obj);
+ return (dbus_uint32_t)(-1);
+ }
+ Py_CLEAR(long_obj);
+ return i;
+}
+
+static PyObject *
+UInt32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_uint32_range_check(self) == (dbus_uint32_t)(-1)
+ && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ return self;
+}
+
+PyTypeObject DBusPyUInt32_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.UInt32",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UInt32_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ UInt32_tp_new, /* tp_new */
+};
+
+/* Int64 =========================================================== */
+
+PyDoc_STRVAR(Int64_tp_doc,
+"A signed 64-bit integer between -0x8000 0000 0000 0000 and\n"
+"+0x7FFF FFFF FFFF FFFF, represented as a subtype of `long`.\n"
+"\n"
+"Note that this may be changed in future to be a subtype of `int` on\n"
+"64-bit platforms; applications should not rely on either behaviour.\n"
+"\n"
+"This type only works on platforms where the C compiler has suitable\n"
+"64-bit types, such as C99 ``long long``.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Int64(value: long[, variant_level: int]) -> Int64\n"
+"\n"
+"``value`` must be within the allowed range, or `OverflowError` will be\n"
+"raised.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an int64, this is represented in Python by an\n"
+" Int64 with variant_level==2.\n"
+);
+
+#ifdef DBUS_PYTHON_64_BIT_WORKS
+dbus_int64_t
+dbus_py_int64_range_check(PyObject *obj)
+{
+ PY_LONG_LONG i;
+ PyObject *long_obj = PyNumber_Long(obj);
+
+ if (!long_obj) return -1;
+ i = PyLong_AsLongLong(long_obj);
+ if (i == -1 && PyErr_Occurred()) {
+ Py_CLEAR(long_obj);
+ return -1;
+ }
+ if (i < INT64_MIN || i > INT64_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "Value out of range for Int64");
+ Py_CLEAR(long_obj);
+ return -1;
+ }
+ Py_CLEAR(long_obj);
+ return i;
+}
+#endif
+
+static PyObject *
+Int64_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+#ifdef DBUS_PYTHON_64_BIT_WORKS
+ PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_int64_range_check(self) == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ return self;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "64-bit types are not available on this platform");
+ return NULL;
+#endif
+}
+
+PyTypeObject DBusPyInt64_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Int64",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Int64_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Int64_tp_new, /* tp_new */
+};
+
+/* UInt64 =========================================================== */
+
+PyDoc_STRVAR(UInt64_tp_doc,
+"An unsigned 64-bit integer between 0 and 0xFFFF FFFF FFFF FFFF,\n"
+"represented as a subtype of `long`.\n"
+"\n"
+"This type only exists on platforms where the C compiler has suitable\n"
+"64-bit types, such as C99 ``unsigned long long``.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.UInt64(value: long[, variant_level: int]) -> UInt64\n"
+"\n"
+"``value`` must be within the allowed range, or `OverflowError` will be\n"
+"raised.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a uint64, this is represented in Python by a\n"
+" UInt64 with variant_level==2.\n"
+);
+
+dbus_uint64_t
+dbus_py_uint64_range_check(PyObject *obj)
+{
+ unsigned PY_LONG_LONG i;
+ PyObject *long_obj = PyNumber_Long(obj);
+
+ if (!long_obj) return (dbus_uint64_t)(-1);
+ i = PyLong_AsUnsignedLongLong(long_obj);
+ if (i == (unsigned PY_LONG_LONG)(-1) && PyErr_Occurred()) {
+ Py_CLEAR(long_obj);
+ return (dbus_uint64_t)(-1);
+ }
+ if (i > UINT64_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "Value out of range for UInt64");
+ Py_CLEAR(long_obj);
+ return (dbus_uint64_t)(-1);
+ }
+ Py_CLEAR(long_obj);
+ return i;
+}
+
+static PyObject *
+UInt64_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+#ifdef DBUS_PYTHON_64_BIT_WORKS
+ PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs);
+ if (self && dbus_py_uint64_range_check(self) == (dbus_uint64_t)(-1)
+ && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ return self;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "64-bit integer types are not supported on this platform");
+ return NULL;
+#endif
+}
+
+PyTypeObject DBusPyUInt64_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.UInt64",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UInt64_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ UInt64_tp_new, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_int_types(void)
+{
+ DBusPyInt16_Type.tp_base = &INTBASE;
+ if (PyType_Ready(&DBusPyInt16_Type) < 0) return 0;
+ /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
+ desired */
+ DBusPyInt16_Type.tp_print = NULL;
+
+ DBusPyUInt16_Type.tp_base = &INTBASE;
+ if (PyType_Ready(&DBusPyUInt16_Type) < 0) return 0;
+ DBusPyUInt16_Type.tp_print = NULL;
+
+ DBusPyInt32_Type.tp_base = &INTBASE;
+ if (PyType_Ready(&DBusPyInt32_Type) < 0) return 0;
+ DBusPyInt32_Type.tp_print = NULL;
+
+ DBusPyUInt32_Type.tp_base = &DBusPyLongBase_Type;
+ if (PyType_Ready(&DBusPyUInt32_Type) < 0) return 0;
+ DBusPyUInt32_Type.tp_print = NULL;
+
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ DBusPyInt64_Type.tp_base = &DBusPyLongBase_Type;
+ if (PyType_Ready(&DBusPyInt64_Type) < 0) return 0;
+ DBusPyInt64_Type.tp_print = NULL;
+
+ DBusPyUInt64_Type.tp_base = &DBusPyLongBase_Type;
+ if (PyType_Ready(&DBusPyUInt64_Type) < 0) return 0;
+ DBusPyUInt64_Type.tp_print = NULL;
+#endif
+
+ DBusPyBoolean_Type.tp_base = &INTBASE;
+ if (PyType_Ready(&DBusPyBoolean_Type) < 0) return 0;
+ DBusPyBoolean_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_int_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyInt16_Type);
+ Py_INCREF(&DBusPyUInt16_Type);
+ Py_INCREF(&DBusPyInt32_Type);
+ Py_INCREF(&DBusPyUInt32_Type);
+ Py_INCREF(&DBusPyInt64_Type);
+ Py_INCREF(&DBusPyUInt64_Type);
+ Py_INCREF(&DBusPyBoolean_Type);
+ if (PyModule_AddObject(this_module, "Int16",
+ (PyObject *)&DBusPyInt16_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt16",
+ (PyObject *)&DBusPyUInt16_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "Int32",
+ (PyObject *)&DBusPyInt32_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt32",
+ (PyObject *)&DBusPyUInt32_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "Int64",
+ (PyObject *)&DBusPyInt64_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt64",
+ (PyObject *)&DBusPyUInt64_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "Boolean",
+ (PyObject *)&DBusPyBoolean_Type) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/libdbusconn.c b/dbus_bindings/libdbusconn.c
new file mode 100644
index 0000000..e9401fe
--- /dev/null
+++ b/dbus_bindings/libdbusconn.c
@@ -0,0 +1,126 @@
+/* An extremely thin wrapper around a libdbus Connection, for use by
+ * Server.
+ *
+ * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+#include "conn-internal.h"
+
+PyDoc_STRVAR(DBusPyLibDBusConnection_tp_doc,
+"A reference to a ``DBusConnection`` from ``libdbus``, which might not\n"
+"have been attached to a `dbus.connection.Connection` yet.\n"
+"\n"
+"Cannot be instantiated from Python. The only use of this object is to\n"
+"pass it to the ``dbus.connection.Connection`` constructor instead of an\n"
+"address.\n"
+);
+
+/** Create a DBusPyLibDBusConnection from a DBusConnection.
+ */
+PyObject *
+DBusPyLibDBusConnection_New(DBusConnection *conn)
+{
+ DBusPyLibDBusConnection *self = NULL;
+
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn);
+
+ self = (DBusPyLibDBusConnection *)(DBusPyLibDBusConnection_Type.tp_alloc(
+ &DBusPyLibDBusConnection_Type, 0));
+
+ if (!self)
+ return NULL;
+
+ self->conn = dbus_connection_ref (conn);
+
+ return (PyObject *)self;
+}
+
+/* Destructor */
+static void
+DBusPyLibDBusConnection_tp_dealloc(Connection *self)
+{
+ DBusConnection *conn = self->conn;
+ PyObject *et, *ev, *etb;
+
+ /* avoid clobbering any pending exception */
+ PyErr_Fetch(&et, &ev, &etb);
+
+ self->conn = NULL;
+
+ if (conn) {
+ dbus_connection_unref(conn);
+ }
+
+ PyErr_Restore(et, ev, etb);
+ (Py_TYPE(self)->tp_free)((PyObject *) self);
+}
+
+PyTypeObject DBusPyLibDBusConnection_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_dbus_bindings._LibDBusConnection",
+ sizeof(DBusPyLibDBusConnection),
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)DBusPyLibDBusConnection_tp_dealloc,
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT,
+ DBusPyLibDBusConnection_tp_doc,
+};
+
+dbus_bool_t
+dbus_py_init_libdbus_conn_types(void)
+{
+ if (PyType_Ready(&DBusPyLibDBusConnection_Type) < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+dbus_bool_t
+dbus_py_insert_libdbus_conn_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&DBusPyLibDBusConnection_Type);
+
+ if (PyModule_AddObject(this_module, "_LibDBusConnection",
+ (PyObject *)&DBusPyLibDBusConnection_Type) < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/mainloop.c b/dbus_bindings/mainloop.c
new file mode 100644
index 0000000..59d1e99
--- /dev/null
+++ b/dbus_bindings/mainloop.c
@@ -0,0 +1,207 @@
+/* Implementation of main-loop integration for dbus-python.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2008 Huang Peng <phuang@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+/* Native mainloop wrapper ========================================= */
+
+PyDoc_STRVAR(NativeMainLoop_tp_doc,
+"Object representing D-Bus main loop integration done in native code.\n"
+"Cannot be instantiated directly.\n"
+);
+
+static PyTypeObject NativeMainLoop_Type;
+
+DEFINE_CHECK(NativeMainLoop)
+
+typedef struct {
+ PyObject_HEAD
+ /* Called with the GIL held, should set a Python exception on error */
+ dbus_bool_t (*set_up_connection_cb)(DBusConnection *, void *);
+ dbus_bool_t (*set_up_server_cb)(DBusServer *, void *);
+ /* Called in a destructor. Must not touch the exception state (use
+ * PyErr_Fetch and PyErr_Restore if necessary). */
+ void (*free_cb)(void *);
+ void *data;
+} NativeMainLoop;
+
+static void NativeMainLoop_tp_dealloc(NativeMainLoop *self)
+{
+ if (self->data && self->free_cb) {
+ (self->free_cb)(self->data);
+ }
+ PyObject_Del((PyObject *)self);
+}
+
+static PyTypeObject NativeMainLoop_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.mainloop.NativeMainLoop",
+ sizeof(NativeMainLoop),
+ 0,
+ (destructor)NativeMainLoop_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NativeMainLoop_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ /* deliberately not callable! */
+ 0, /* tp_new */
+};
+
+/* Internal C API for Connection, Bus, Server ======================= */
+
+dbus_bool_t
+dbus_py_check_mainloop_sanity(PyObject *mainloop)
+{
+ if (NativeMainLoop_Check(mainloop)) {
+ return TRUE;
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "A dbus.mainloop.NativeMainLoop instance is required");
+ return FALSE;
+}
+
+dbus_bool_t
+dbus_py_set_up_connection(PyObject *conn, PyObject *mainloop)
+{
+ if (NativeMainLoop_Check(mainloop)) {
+ /* Native mainloops are allowed to do arbitrary strange things */
+ NativeMainLoop *nml = (NativeMainLoop *)mainloop;
+ DBusConnection *dbc = DBusPyConnection_BorrowDBusConnection(conn);
+
+ if (!dbc) {
+ return FALSE;
+ }
+ return (nml->set_up_connection_cb)(dbc, nml->data);
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "A dbus.mainloop.NativeMainLoop instance is required");
+ return FALSE;
+}
+
+dbus_bool_t
+dbus_py_set_up_server(PyObject *server, PyObject *mainloop)
+{
+ if (NativeMainLoop_Check(mainloop)) {
+ /* Native mainloops are allowed to do arbitrary strange things */
+ NativeMainLoop *nml = (NativeMainLoop *)mainloop;
+ DBusServer *dbs = DBusPyServer_BorrowDBusServer(server);
+
+ if (!dbs) {
+ return FALSE;
+ }
+ return (nml->set_up_server_cb)(dbs, nml->data);
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "A dbus.mainloop.NativeMainLoop instance is required");
+ return FALSE;
+}
+
+/* C API ============================================================ */
+
+PyObject *
+DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
+ dbus_bool_t (*server_cb)(DBusServer *, void *),
+ void (*free_cb)(void *),
+ void *data)
+{
+ NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoop_Type);
+ if (self) {
+ self->data = data;
+ self->free_cb = free_cb;
+ self->set_up_connection_cb = conn_cb;
+ self->set_up_server_cb = server_cb;
+ }
+ return (PyObject *)self;
+}
+
+/* Null mainloop implementation ===================================== */
+
+static dbus_bool_t
+noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
+{
+ return TRUE;
+}
+
+#define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
+#define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
+
+/* Initialization =================================================== */
+
+dbus_bool_t
+dbus_py_init_mainloop(void)
+{
+ if (PyType_Ready (&NativeMainLoop_Type) < 0) return 0;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_mainloop_types(PyObject *this_module)
+{
+ PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
+ noop_server_cb,
+ NULL,
+ NULL);
+ if (!null_main_loop) return 0;
+
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&NativeMainLoop_Type);
+ if (PyModule_AddObject (this_module, "NativeMainLoop",
+ (PyObject *)&NativeMainLoop_Type) < 0) return 0;
+ if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP",
+ null_main_loop) < 0) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/message-append.c b/dbus_bindings/message-append.c
new file mode 100644
index 0000000..d20b493
--- /dev/null
+++ b/dbus_bindings/message-append.c
@@ -0,0 +1,1293 @@
+/* D-Bus Message serialization. This contains all the logic to map from
+ * Python objects to D-Bus types.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <assert.h>
+
+#define DBG_IS_TOO_VERBOSE
+#include "compat-internal.h"
+#include "types-internal.h"
+#include "message-internal.h"
+
+/* Return the number of variants wrapping the given object. Return 0
+ * if the object is not a D-Bus type.
+ */
+static long
+get_variant_level(PyObject *obj)
+{
+ if (DBusPyString_Check(obj)) {
+ return ((DBusPyString *)obj)->variant_level;
+ }
+#ifndef PY3
+ else if (DBusPyIntBase_Check(obj)) {
+ return ((DBusPyIntBase *)obj)->variant_level;
+ }
+#endif
+ else if (DBusPyFloatBase_Check(obj)) {
+ return ((DBusPyFloatBase *)obj)->variant_level;
+ }
+ else if (DBusPyArray_Check(obj)) {
+ return ((DBusPyArray *)obj)->variant_level;
+ }
+ else if (DBusPyDict_Check(obj)) {
+ return ((DBusPyDict *)obj)->variant_level;
+ }
+ else if (DBusPyLongBase_Check(obj) ||
+#ifdef PY3
+ DBusPyBytesBase_Check(obj) ||
+#endif
+ DBusPyStrBase_Check(obj) ||
+ DBusPyStruct_Check(obj)) {
+ return dbus_py_variant_level_get(obj);
+ }
+ else {
+ return 0;
+ }
+}
+
+char dbus_py_Message_append__doc__[] = (
+"set_args(*args[, **kwargs])\n\n"
+"Set the message's arguments from the positional parameter, according to\n"
+"the signature given by the ``signature`` keyword parameter.\n"
+"\n"
+"The following type conversions are supported:\n\n"
+"=============================== ===========================\n"
+"D-Bus (in signature) Python\n"
+"=============================== ===========================\n"
+"boolean (b) any object (via bool())\n"
+"byte (y) string of length 1\n"
+" any integer\n"
+"any integer type any integer\n"
+"double (d) any float\n"
+"object path anything with a __dbus_object_path__ attribute\n"
+"string, signature, object path str (must be UTF-8) or unicode\n"
+"dict (a{...}) any mapping\n"
+"array (a...) any iterable over appropriate objects\n"
+"struct ((...)) any iterable over appropriate objects\n"
+"variant any object above (guess type as below)\n"
+"=============================== ===========================\n"
+"\n"
+"Here 'any integer' means anything on which int() or long()\n"
+"(as appropriate) will work, except for basestring subclasses.\n"
+"'Any float' means anything on which float() will work, except\n"
+"for basestring subclasses.\n"
+"\n"
+"If there is no signature, guess from the arguments using\n"
+"the static method `Message.guess_signature`.\n"
+);
+
+char dbus_py_Message_guess_signature__doc__[] = (
+"guess_signature(*args) -> Signature [static method]\n\n"
+"Guess a D-Bus signature which should be used to encode the given\n"
+"Python objects.\n"
+"\n"
+"The signature is constructed as follows:\n\n"
+"+-------------------------------+---------------------------+\n"
+"|Python |D-Bus |\n"
+"+===============================+===========================+\n"
+"|D-Bus type, variant_level > 0 |variant (v) |\n"
+"+-------------------------------+---------------------------+\n"
+"|D-Bus type, variant_level == 0 |the corresponding type |\n"
+"+-------------------------------+---------------------------+\n"
+"|anything with a |object path |\n"
+"|__dbus_object_path__ attribute | |\n"
+"+-------------------------------+---------------------------+\n"
+"|bool |boolean (y) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other int subclass |int32 (i) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other long subclass |int64 (x) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other float subclass |double (d) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other str subclass |string (s) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other unicode subclass |string (s) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other tuple subclass |struct ((...)) |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other list subclass |array (a...), guess |\n"
+"| |contents' type according to|\n"
+"| |type of first item |\n"
+"+-------------------------------+---------------------------+\n"
+"|any other dict subclass |dict (a{...}), guess key, |\n"
+"| |value type according to |\n"
+"| |types for an arbitrary item|\n"
+"+-------------------------------+---------------------------+\n"
+"|anything else |raise TypeError |\n"
+"+-------------------------------+---------------------------+\n"
+);
+
+/* return a new reference, possibly to None */
+static PyObject *
+get_object_path(PyObject *obj)
+{
+ PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
+
+ if (magic_attr) {
+ if (PyUnicode_Check(magic_attr) || PyBytes_Check(magic_attr)) {
+ return magic_attr;
+ }
+ else {
+ Py_CLEAR(magic_attr);
+ PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
+ "a string");
+ return NULL;
+ }
+ }
+ else {
+ /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
+ if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
+ PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
+ return NULL;
+ PyErr_Clear();
+ Py_RETURN_NONE;
+ }
+}
+
+/* Return a new reference. If the object is a variant and variant_level_ptr
+ * is not NULL, put the variant level in the variable pointed to, and
+ * return the contained type instead of "v". */
+static PyObject *
+_signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
+{
+ PyObject *magic_attr;
+ long variant_level = get_variant_level(obj);
+
+ if (variant_level < 0)
+ return NULL;
+
+ if (variant_level_ptr) {
+ *variant_level_ptr = variant_level;
+ }
+ else if (variant_level > 0) {
+ return NATIVESTR_FROMSTR(DBUS_TYPE_VARIANT_AS_STRING);
+ }
+
+ if (obj == Py_True || obj == Py_False) {
+ return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
+ }
+
+ magic_attr = get_object_path(obj);
+ if (!magic_attr)
+ return NULL;
+ if (magic_attr != Py_None) {
+ Py_CLEAR(magic_attr);
+ return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
+ }
+ Py_CLEAR(magic_attr);
+
+ /* Ordering is important: some of these are subclasses of each other. */
+#ifdef PY3
+ if (PyLong_Check(obj)) {
+ if (DBusPyUInt64_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
+ else if (DBusPyInt64_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
+ else if (DBusPyUInt32_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
+ else if (DBusPyInt32_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
+ else if (DBusPyUInt16_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
+ else if (DBusPyInt16_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
+ else if (DBusPyByte_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
+ else if (DBusPyBoolean_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
+ else
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
+ }
+#else /* !PY3 */
+ if (PyInt_Check(obj)) {
+ if (DBusPyInt16_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
+ else if (DBusPyInt32_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
+ else if (DBusPyByte_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
+ else if (DBusPyUInt16_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
+ else if (DBusPyBoolean_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
+ else
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
+ }
+ else if (PyLong_Check(obj)) {
+ if (DBusPyInt64_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
+ else if (DBusPyUInt32_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
+ else if (DBusPyUInt64_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
+ else
+ return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
+ }
+#endif /* PY3 */
+ else if (PyUnicode_Check(obj)) {
+ /* Object paths and signatures are unicode subtypes in Python 3
+ * (the first two cases will never be true in Python 2) */
+ if (DBusPyObjectPath_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
+ else if (DBusPySignature_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
+ else
+ return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
+ }
+#if defined(DBUS_TYPE_UNIX_FD)
+ else if (DBusPyUnixFd_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_UNIX_FD_AS_STRING);
+#endif
+ else if (PyFloat_Check(obj)) {
+#ifdef WITH_DBUS_FLOAT32
+ if (DBusPyDouble_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
+ else if (DBusPyFloat_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_FLOAT_AS_STRING);
+ else
+#endif
+ return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
+ }
+ else if (PyBytes_Check(obj)) {
+ /* Object paths and signatures are bytes subtypes in Python 2
+ * (the first two cases will never be true in Python 3) */
+ if (DBusPyObjectPath_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
+ else if (DBusPySignature_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
+ else if (DBusPyByteArray_Check(obj))
+ return NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING);
+ else
+ return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
+ }
+ else if (PyTuple_Check(obj)) {
+ Py_ssize_t len = PyTuple_GET_SIZE(obj);
+ PyObject *list = PyList_New(len + 2); /* new ref */
+ PyObject *item; /* temporary new ref */
+ PyObject *empty_str; /* temporary new ref */
+ PyObject *ret;
+ Py_ssize_t i;
+
+ if (!list) return NULL;
+ if (len == 0) {
+ PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
+ Py_CLEAR(list);
+ return NULL;
+ }
+ /* Set the first and last elements of list to be the parentheses */
+ item = NATIVESTR_FROMSTR(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
+ if (PyList_SetItem(list, 0, item) < 0) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ item = NATIVESTR_FROMSTR(DBUS_STRUCT_END_CHAR_AS_STRING);
+ if (PyList_SetItem(list, len + 1, item) < 0) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ if (!item || !PyList_GET_ITEM(list, 0)) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ item = NULL;
+
+ for (i = 0; i < len; i++) {
+ item = PyTuple_GetItem(obj, i);
+ if (!item) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ item = _signature_string_from_pyobject(item, NULL);
+ if (!item) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ if (PyList_SetItem(list, i + 1, item) < 0) {
+ Py_CLEAR(list);
+ return NULL;
+ }
+ item = NULL;
+ }
+ empty_str = NATIVESTR_FROMSTR("");
+ if (!empty_str) {
+ /* really shouldn't happen */
+ Py_CLEAR(list);
+ return NULL;
+ }
+ ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
+ /* whether ret is NULL or not, */
+ Py_CLEAR(empty_str);
+ Py_CLEAR(list);
+ return ret;
+ }
+ else if (PyList_Check(obj)) {
+ PyObject *tmp;
+ PyObject *ret = NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING);
+ if (!ret) return NULL;
+#ifdef PY3
+ if (DBusPyArray_Check(obj) &&
+ PyUnicode_Check(((DBusPyArray *)obj)->signature))
+ {
+ PyObject *concat = PyUnicode_Concat(
+ ret, ((DBusPyArray *)obj)->signature);
+ Py_CLEAR(ret);
+ return concat;
+ }
+#else
+ if (DBusPyArray_Check(obj) &&
+ PyBytes_Check(((DBusPyArray *)obj)->signature))
+ {
+ PyBytes_Concat(&ret, ((DBusPyArray *)obj)->signature);
+ return ret;
+ }
+#endif
+ if (PyList_GET_SIZE(obj) == 0) {
+ /* No items, so fail. Or should we guess "av"? */
+ PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
+ "from an empty list");
+ return NULL;
+ }
+ tmp = PyList_GetItem(obj, 0);
+ tmp = _signature_string_from_pyobject(tmp, NULL);
+ if (!tmp) return NULL;
+#ifdef PY3
+ {
+ PyObject *concat = PyUnicode_Concat(ret, tmp);
+ Py_CLEAR(ret);
+ Py_CLEAR(tmp);
+ return concat;
+ }
+#else
+ PyBytes_ConcatAndDel(&ret, tmp);
+ return ret;
+#endif
+ }
+ else if (PyDict_Check(obj)) {
+ PyObject *key, *value, *keysig, *valuesig;
+ Py_ssize_t pos = 0;
+ PyObject *ret = NULL;
+
+#ifdef PY3
+ if (DBusPyDict_Check(obj) &&
+ PyUnicode_Check(((DBusPyDict *)obj)->signature))
+ {
+ return PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ "%U"
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+ ((DBusPyDict *)obj)->signature);
+ }
+#else
+ if (DBusPyDict_Check(obj) &&
+ PyBytes_Check(((DBusPyDict *)obj)->signature))
+ {
+ const char *sig = PyBytes_AS_STRING(((DBusPyDict *)obj)->signature);
+
+ return PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ "%s"
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+ sig);
+ }
+#endif
+ if (!PyDict_Next(obj, &pos, &key, &value)) {
+ /* No items, so fail. Or should we guess "a{vv}"? */
+ PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
+ "from an empty dict");
+ return NULL;
+ }
+ keysig = _signature_string_from_pyobject(key, NULL);
+ valuesig = _signature_string_from_pyobject(value, NULL);
+ if (keysig && valuesig) {
+#ifdef PY3
+ ret = PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ "%U%U"
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+ keysig, valuesig);
+#else
+ ret = PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ "%s%s"
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+ PyBytes_AS_STRING(keysig),
+ PyBytes_AS_STRING(valuesig));
+#endif
+ }
+ Py_CLEAR(keysig);
+ Py_CLEAR(valuesig);
+ return ret;
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "Don't know which D-Bus type "
+ "to use to encode type \"%s\"",
+ Py_TYPE(obj)->tp_name);
+ return NULL;
+ }
+}
+
+PyObject *
+dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
+{
+ PyObject *tmp, *ret = NULL;
+
+ if (!args) {
+ if (!PyErr_Occurred()) {
+ PyErr_BadInternalCall();
+ }
+ return NULL;
+ }
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
+ PyObject_Print(args, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ if (!PyTuple_Check(args)) {
+ DBG("%s", "Message_guess_signature: args not a tuple");
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ /* if there were no args, easy */
+ if (PyTuple_GET_SIZE(args) == 0) {
+ DBG("%s", "Message_guess_signature: no args, so return Signature('')");
+ return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
+ }
+
+ /* if there were args, the signature we want is, by construction,
+ * exactly the signature we get for the tuple args, except that we don't
+ * want the parentheses. */
+ tmp = _signature_string_from_pyobject(args, NULL);
+ if (!tmp) {
+ DBG("%s", "Message_guess_signature: failed");
+ return NULL;
+ }
+ if (PyUnicode_Check(tmp)) {
+ PyObject *as_bytes = PyUnicode_AsUTF8String(tmp);
+ Py_CLEAR(tmp);
+ if (!as_bytes)
+ return NULL;
+ if (PyBytes_GET_SIZE(as_bytes) < 2) {
+ PyErr_SetString(PyExc_RuntimeError, "Internal error: "
+ "_signature_string_from_pyobject returned "
+ "a bad result");
+ Py_CLEAR(as_bytes);
+ return NULL;
+ }
+ tmp = as_bytes;
+ }
+ if (!PyBytes_Check(tmp) || PyBytes_GET_SIZE(tmp) < 2) {
+ PyErr_SetString(PyExc_RuntimeError, "Internal error: "
+ "_signature_string_from_pyobject returned "
+ "a bad result");
+ Py_CLEAR(tmp);
+ return NULL;
+ }
+ ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
+ PyBytes_AS_STRING(tmp) + 1,
+ PyBytes_GET_SIZE(tmp) - 2);
+ Py_CLEAR(tmp);
+ return ret;
+}
+
+static int _message_iter_append_pyobject(DBusMessageIter *appender,
+ DBusSignatureIter *sig_iter,
+ PyObject *obj,
+ dbus_bool_t *more);
+static int _message_iter_append_variant(DBusMessageIter *appender,
+ PyObject *obj);
+
+static int
+_message_iter_append_string(DBusMessageIter *appender,
+ int sig_type, PyObject *obj,
+ dbus_bool_t allow_object_path_attr)
+{
+ char *s;
+ PyObject *utf8;
+
+ if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
+ PyObject *object_path = get_object_path (obj);
+
+ if (object_path == Py_None) {
+ Py_CLEAR(object_path);
+ }
+ else if (!object_path) {
+ return -1;
+ }
+ else {
+ int ret = _message_iter_append_string(appender, sig_type,
+ object_path, FALSE);
+ Py_CLEAR(object_path);
+ return ret;
+ }
+ }
+
+ if (PyBytes_Check(obj)) {
+ utf8 = obj;
+ Py_INCREF(obj);
+ }
+ else if (PyUnicode_Check(obj)) {
+ utf8 = PyUnicode_AsUTF8String(obj);
+ if (!utf8) return -1;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected a string or unicode object");
+ return -1;
+ }
+
+ /* Raise TypeError if the string has embedded NULs */
+ if (PyBytes_AsStringAndSize(utf8, &s, NULL) < 0)
+ return -1;
+
+ /* Validate UTF-8, strictly */
+ if (!dbus_validate_utf8(s, NULL)) {
+ PyErr_SetString(PyExc_UnicodeError, "String parameters "
+ "to be sent over D-Bus must be valid UTF-8 "
+ "with no noncharacter code points");
+ return -1;
+ }
+
+ DBG("Performing actual append: string (from unicode) %s", s);
+ if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
+ Py_CLEAR(utf8);
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ Py_CLEAR(utf8);
+ return 0;
+}
+
+static int
+_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
+{
+ unsigned char y;
+
+ if (PyBytes_Check(obj)) {
+ if (PyBytes_GET_SIZE(obj) != 1) {
+ PyErr_Format(PyExc_ValueError,
+ "Expected a length-1 bytes but found %d bytes",
+ (int)PyBytes_GET_SIZE(obj));
+ return -1;
+ }
+ y = *(unsigned char *)PyBytes_AS_STRING(obj);
+ }
+ else {
+ /* on Python 2 this accepts either int or long */
+ long i = PyLong_AsLong(obj);
+
+ if (i == -1 && PyErr_Occurred()) return -1;
+ if (i < 0 || i > 0xff) {
+ PyErr_Format(PyExc_ValueError,
+ "%d outside range for a byte value",
+ (int)i);
+ return -1;
+ }
+ y = i;
+ }
+ DBG("Performing actual append: byte \\x%02x", (unsigned)y);
+ if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+static dbus_bool_t
+dbuspy_message_iter_close_container(DBusMessageIter *iter,
+ DBusMessageIter *sub,
+ dbus_bool_t is_ok)
+{
+ if (!is_ok) {
+ dbus_message_iter_abandon_container(iter, sub);
+ return TRUE;
+ }
+ return dbus_message_iter_close_container(iter, sub);
+}
+
+#if defined(DBUS_TYPE_UNIX_FD)
+static int
+_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
+{
+ int fd;
+ long original_fd;
+
+ if (INTORLONG_CHECK(obj))
+ {
+ /* on Python 2 this accepts either int or long */
+ original_fd = PyLong_AsLong(obj);
+ if (original_fd == -1 && PyErr_Occurred())
+ return -1;
+ if (original_fd < INT_MIN || original_fd > INT_MAX) {
+ PyErr_Format(PyExc_ValueError, "out of int range: %ld",
+ original_fd);
+ return -1;
+ }
+ fd = (int)original_fd;
+ }
+ else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
+ fd = dbus_py_unix_fd_get_fd(obj);
+ }
+ else {
+ return -1;
+ }
+
+ DBG("Performing actual append: fd %d", fd);
+ if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+static int
+_message_iter_append_dictentry(DBusMessageIter *appender,
+ DBusSignatureIter *sig_iter,
+ PyObject *dict, PyObject *key)
+{
+ DBusSignatureIter sub_sig_iter;
+ DBusMessageIter sub;
+ int ret = -1;
+ PyObject *value = PyObject_GetItem(dict, key);
+ dbus_bool_t more;
+
+ if (!value) return -1;
+
+#ifdef USING_DBG
+ fprintf(stderr, "Append dictentry: ");
+ PyObject_Print(key, stderr, 0);
+ fprintf(stderr, " => ");
+ PyObject_Print(value, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
+ dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
+#ifdef USING_DBG
+ {
+ char *s;
+ s = dbus_signature_iter_get_signature(sig_iter);
+ DBG("Signature of parent iterator %p is %s", sig_iter, s);
+ dbus_free(s);
+ s = dbus_signature_iter_get_signature(&sub_sig_iter);
+ DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
+ dbus_free(s);
+ }
+#endif
+
+ DBG("%s", "Opening DICT_ENTRY container");
+ if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
+ NULL, &sub)) {
+ PyErr_NoMemory();
+ goto out;
+ }
+ ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
+ if (ret == 0) {
+ ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
+ }
+ DBG("%s", "Closing DICT_ENTRY container");
+ if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+out:
+ Py_CLEAR(value);
+ return ret;
+}
+
+static int
+_message_iter_append_multi(DBusMessageIter *appender,
+ const DBusSignatureIter *sig_iter,
+ int mode, PyObject *obj)
+{
+ DBusMessageIter sub_appender;
+ DBusSignatureIter sub_sig_iter;
+ PyObject *contents;
+ int ret;
+ PyObject *iterator = PyObject_GetIter(obj);
+ char *sig = NULL;
+ int container = mode;
+ dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
+ int inner_type;
+ dbus_bool_t more;
+
+ assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
+ mode == DBUS_TYPE_STRUCT);
+
+#ifdef USING_DBG
+ fprintf(stderr, "Appending multiple: ");
+ PyObject_Print(obj, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ if (!iterator) return -1;
+ if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
+
+ DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
+ dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
+#ifdef USING_DBG
+ {
+ char *s;
+ s = dbus_signature_iter_get_signature(sig_iter);
+ DBG("Signature of parent iterator %p is %s", sig_iter, s);
+ dbus_free(s);
+ s = dbus_signature_iter_get_signature(&sub_sig_iter);
+ DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
+ dbus_free(s);
+ }
+#endif
+ inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
+
+ if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
+ sig = dbus_signature_iter_get_signature(&sub_sig_iter);
+ if (!sig) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+ }
+ /* else leave sig set to NULL. */
+
+ DBG("Opening '%c' container", container);
+ if (!dbus_message_iter_open_container(appender, container,
+ sig, &sub_appender)) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+ ret = 0;
+ more = TRUE;
+ while ((contents = PyIter_Next(iterator))) {
+
+ if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
+ DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
+ dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
+#ifdef USING_DBG
+ {
+ char *s;
+ s = dbus_signature_iter_get_signature(sig_iter);
+ DBG("Signature of parent iterator %p is %s", sig_iter, s);
+ dbus_free(s);
+ s = dbus_signature_iter_get_signature(&sub_sig_iter);
+ DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
+ dbus_free(s);
+ }
+#endif
+ }
+ else /* struct */ {
+ if (!more) {
+ PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
+ "D-Bus signature than in Python arguments ");
+ ret = -1;
+ break;
+ }
+ }
+
+ if (mode == DBUS_TYPE_DICT_ENTRY) {
+ ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
+ obj, contents);
+ }
+ else if (mode == DBUS_TYPE_ARRAY && is_byte_array
+ && inner_type == DBUS_TYPE_VARIANT) {
+ /* Subscripting a ByteArray gives a str of length 1, but if the
+ * container is a ByteArray and the parameter is an array of
+ * variants, we want to produce an array of variants containing
+ * bytes, not strings.
+ */
+ PyObject *args = Py_BuildValue("(O)", contents);
+ PyObject *byte;
+
+ if (!args)
+ break;
+ byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
+ Py_CLEAR(args);
+ if (!byte)
+ break;
+ ret = _message_iter_append_variant(&sub_appender, byte);
+ Py_CLEAR(byte);
+ }
+ else {
+ /* advances sub_sig_iter and sets more on success - for array
+ * this doesn't matter, for struct it's essential */
+ ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
+ contents, &more);
+ }
+
+ Py_CLEAR(contents);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+ if (PyErr_Occurred()) {
+ ret = -1;
+ }
+ else if (mode == DBUS_TYPE_STRUCT && more) {
+ PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
+ "signature than in Python arguments ");
+ ret = -1;
+ }
+
+ /* This must be run as cleanup, even on failure. */
+ DBG("Closing '%c' container", container);
+ if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+
+out:
+ Py_CLEAR(iterator);
+ dbus_free(sig);
+ return ret;
+}
+
+static int
+_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
+ PyObject *obj)
+{
+ /* a bit of a faster path for byte arrays that are strings */
+ Py_ssize_t len = PyBytes_GET_SIZE(obj);
+ const char *s;
+ DBusMessageIter sub;
+ int ret;
+
+ s = PyBytes_AS_STRING(obj);
+ DBG("%s", "Opening ARRAY container");
+ if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &sub)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ DBG("Appending fixed array of %d bytes", (int)len);
+ if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
+ ret = 0;
+ }
+ else {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+ DBG("%s", "Closing ARRAY container");
+ if (!dbus_message_iter_close_container(appender, &sub)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return ret;
+}
+
+/* Encode some Python object into a D-Bus variant slot. */
+static int
+_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
+{
+ DBusSignatureIter obj_sig_iter;
+ const char *obj_sig_str;
+ PyObject *obj_sig;
+ int ret;
+ long variant_level;
+ dbus_bool_t dummy;
+ DBusMessageIter *variant_iters = NULL;
+
+ /* Separate the object into the contained object, and the number of
+ * variants it's wrapped in. */
+ obj_sig = _signature_string_from_pyobject(obj, &variant_level);
+ if (!obj_sig) return -1;
+
+ if (PyUnicode_Check(obj_sig)) {
+ PyObject *obj_sig_as_bytes = PyUnicode_AsUTF8String(obj_sig);
+ Py_CLEAR(obj_sig);
+ if (!obj_sig_as_bytes)
+ return -1;
+ obj_sig = obj_sig_as_bytes;
+ }
+ obj_sig_str = PyBytes_AsString(obj_sig);
+ if (!obj_sig_str) {
+ Py_CLEAR(obj_sig);
+ return -1;
+ }
+
+ if (variant_level < 1) {
+ variant_level = 1;
+ }
+
+ dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
+
+ {
+ long i;
+
+ variant_iters = calloc (variant_level, sizeof (DBusMessageIter));
+
+ if (!variant_iters) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+
+ for (i = 0; i < variant_level; i++) {
+ DBusMessageIter *child = &variant_iters[i];
+ /* The first is a special case: its parent is the iter passed in
+ * to this function, instead of being the previous one in the
+ * stack
+ */
+ DBusMessageIter *parent = (i == 0
+ ? appender
+ : &(variant_iters[i-1]));
+ /* The last is also a special case: it contains the actual
+ * object, rather than another variant
+ */
+ const char *sig_str = (i == variant_level-1
+ ? obj_sig_str
+ : DBUS_TYPE_VARIANT_AS_STRING);
+
+ DBG("Opening VARIANT container %p inside %p containing '%s'",
+ child, parent, sig_str);
+ if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
+ sig_str, child)) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* Put the object itself into the innermost variant */
+ ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
+ &obj_sig_iter, obj, &dummy);
+
+ /* here we rely on i (and variant_level) being a signed long */
+ for (i = variant_level - 1; i >= 0; i--) {
+ DBusMessageIter *child = &variant_iters[i];
+ /* The first is a special case: its parent is the iter passed in
+ * to this function, instead of being the previous one in the
+ * stack
+ */
+ DBusMessageIter *parent = (i == 0 ? appender
+ : &(variant_iters[i-1]));
+
+ DBG("Closing VARIANT container %p inside %p", child, parent);
+ if (!dbus_message_iter_close_container(parent, child)) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (variant_iters != NULL)
+ free (variant_iters);
+
+ Py_CLEAR(obj_sig);
+ return ret;
+}
+
+/* On success, *more is set to whether there's more in the signature. */
+static int
+_message_iter_append_pyobject(DBusMessageIter *appender,
+ DBusSignatureIter *sig_iter,
+ PyObject *obj,
+ dbus_bool_t *more)
+{
+ int sig_type = dbus_signature_iter_get_current_type(sig_iter);
+ DBusBasicValue u;
+ int ret = -1;
+
+#ifdef USING_DBG
+ fprintf(stderr, "Appending object at %p: ", obj);
+ PyObject_Print(obj, stderr, 0);
+ fprintf(stderr, " into appender at %p, dbus wants type %c\n",
+ appender, sig_type);
+#endif
+
+ switch (sig_type) {
+ /* The numeric types are relatively simple to deal with, so are
+ * inlined here. */
+
+ case DBUS_TYPE_BOOLEAN:
+ if (PyObject_IsTrue(obj)) {
+ u.bool_val = 1;
+ }
+ else {
+ u.bool_val = 0;
+ }
+ DBG("Performing actual append: bool(%ld)", (long)u.bool_val);
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.bool_val)) {
+ PyErr_NoMemory();
+ ret = -1;
+ break;
+ }
+ ret = 0;
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ u.dbl = PyFloat_AsDouble(obj);
+ if (PyErr_Occurred()) {
+ ret = -1;
+ break;
+ }
+ DBG("Performing actual append: double(%f)", u.dbl);
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.dbl)) {
+ PyErr_NoMemory();
+ ret = -1;
+ break;
+ }
+ ret = 0;
+ break;
+
+#ifdef WITH_DBUS_FLOAT32
+ case DBUS_TYPE_FLOAT:
+ u.dbl = PyFloat_AsDouble(obj);
+ if (PyErr_Occurred()) {
+ ret = -1;
+ break;
+ }
+ /* FIXME: DBusBasicValue will need to grow a float member if
+ * float32 becomes supported */
+ u.f = (float)u.dbl;
+ DBG("Performing actual append: float(%f)", u.f);
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
+ PyErr_NoMemory();
+ ret = -1;
+ break;
+ }
+ ret = 0;
+ break;
+#endif
+
+ /* The integer types are all basically the same - we delegate to
+ intNN_range_check() */
+#define PROCESS_INTEGER(size, member) \
+ u.member = dbus_py_##size##_range_check(obj);\
+ if (u.member == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
+ ret = -1; \
+ break; \
+ }\
+ DBG("Performing actual append: " #size "(%lld)", (long long)u.member); \
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.member)) {\
+ PyErr_NoMemory();\
+ ret = -1;\
+ break;\
+ } \
+ ret = 0;
+
+ case DBUS_TYPE_INT16:
+ PROCESS_INTEGER(int16, i16)
+ break;
+ case DBUS_TYPE_UINT16:
+ PROCESS_INTEGER(uint16, u16)
+ break;
+ case DBUS_TYPE_INT32:
+ PROCESS_INTEGER(int32, i32)
+ break;
+ case DBUS_TYPE_UINT32:
+ PROCESS_INTEGER(uint32, u32)
+ break;
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ case DBUS_TYPE_INT64:
+ PROCESS_INTEGER(int64, i64)
+ break;
+ case DBUS_TYPE_UINT64:
+ PROCESS_INTEGER(uint64, u64)
+ break;
+#else
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
+ "types are not supported on this platform");
+ ret = -1;
+ break;
+#endif
+#undef PROCESS_INTEGER
+
+ /* Now the more complicated cases, which are delegated to helper
+ * functions (although in practice, the compiler will hopefully
+ * inline them anyway). */
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_OBJECT_PATH:
+ ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
+ break;
+
+ case DBUS_TYPE_BYTE:
+ ret = _message_iter_append_byte(appender, obj);
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ /* 3 cases - it might actually be a dict, or it might be a byte array
+ * being copied from a string (for which we have a faster path),
+ * or it might be a generic array. */
+
+ sig_type = dbus_signature_iter_get_element_type(sig_iter);
+ if (sig_type == DBUS_TYPE_DICT_ENTRY)
+ ret = _message_iter_append_multi(appender, sig_iter,
+ DBUS_TYPE_DICT_ENTRY, obj);
+ else if (sig_type == DBUS_TYPE_BYTE && PyBytes_Check(obj))
+ ret = _message_iter_append_string_as_byte_array(appender, obj);
+ else
+ ret = _message_iter_append_multi(appender, sig_iter,
+ DBUS_TYPE_ARRAY, obj);
+ DBG("_message_iter_append_multi(): %d", ret);
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ ret = _message_iter_append_variant(appender, obj);
+ break;
+
+ case DBUS_TYPE_INVALID:
+ PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
+ "signature than in Python arguments");
+ ret = -1;
+ break;
+
+#if defined(DBUS_TYPE_UNIX_FD)
+ case DBUS_TYPE_UNIX_FD:
+ ret = _message_iter_append_unixfd(appender, obj);
+ break;
+#endif
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
+ "signature", sig_type);
+ ret = -1;
+ break;
+ }
+ if (ret < 0) return -1;
+
+ DBG("Advancing signature iter at %p", sig_iter);
+ *more = dbus_signature_iter_next(sig_iter);
+#ifdef USING_DBG
+ DBG("- result: %ld, type %02x '%c'", (long)(*more),
+ (int)dbus_signature_iter_get_current_type(sig_iter),
+ (int)dbus_signature_iter_get_current_type(sig_iter));
+#endif
+ return 0;
+}
+
+
+PyObject *
+dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
+{
+ const char *signature = NULL;
+ PyObject *signature_obj = NULL;
+ DBusSignatureIter sig_iter;
+ DBusMessageIter appender;
+ static char *argnames[] = {"signature", NULL};
+ dbus_bool_t more;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
+ PyObject_Print(args, stderr, 0);
+ if (kwargs) {
+ fprintf(stderr, ", **");
+ PyObject_Print(kwargs, stderr, 0);
+ }
+ fprintf(stderr, ")\n");
+#endif
+
+ /* only use kwargs for this step: deliberately ignore args for now */
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
+ argnames, &signature)) return NULL;
+
+ if (!signature) {
+ DBG("%s", "No signature for message, guessing...");
+ signature_obj = dbus_py_Message_guess_signature(NULL, args);
+ if (!signature_obj) return NULL;
+ if (PyUnicode_Check(signature_obj)) {
+ PyObject *signature_as_bytes;
+ signature_as_bytes = PyUnicode_AsUTF8String(signature_obj);
+ Py_CLEAR(signature_obj);
+ if (!signature_as_bytes)
+ return NULL;
+ signature_obj = signature_as_bytes;
+ }
+ else {
+ assert(PyBytes_Check(signature_obj));
+ }
+ signature = PyBytes_AS_STRING(signature_obj);
+ }
+ /* from here onwards, you have to do a goto rather than returning NULL
+ to make sure signature_obj gets freed */
+
+ /* iterate over args and the signature, together */
+ if (!dbus_signature_validate(signature, NULL)) {
+ PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
+ goto err;
+ }
+ dbus_message_iter_init_append(self->msg, &appender);
+
+ if (signature[0] != '\0') {
+ int i = 0;
+
+ more = TRUE;
+ dbus_signature_iter_init(&sig_iter, signature);
+ while (more) {
+ if (i >= PyTuple_GET_SIZE(args)) {
+ PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
+ "signature than in Python arguments");
+ goto hosed;
+ }
+ if (_message_iter_append_pyobject(&appender, &sig_iter,
+ PyTuple_GET_ITEM(args, i),
+ &more) < 0) {
+ goto hosed;
+ }
+ i++;
+ }
+ if (i < PyTuple_GET_SIZE(args)) {
+ PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
+ "signature than in Python arguments");
+ goto hosed;
+ }
+ }
+
+ /* success! */
+ Py_CLEAR(signature_obj);
+ Py_RETURN_NONE;
+
+hosed:
+ /* "If appending any of the arguments fails due to lack of memory,
+ * generally the message is hosed and you have to start over" -libdbus docs
+ * Enforce this by throwing away the message structure.
+ */
+ dbus_message_unref(self->msg);
+ self->msg = NULL;
+err:
+ Py_CLEAR(signature_obj);
+ return NULL;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/message-get-args.c b/dbus_bindings/message-get-args.c
new file mode 100644
index 0000000..49670c1
--- /dev/null
+++ b/dbus_bindings/message-get-args.c
@@ -0,0 +1,558 @@
+/* D-Bus Message unserialization. This contains all the logic to map from
+ * D-Bus types to Python objects.
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#define DBG_IS_TOO_VERBOSE
+#include "compat-internal.h"
+#include "types-internal.h"
+#include "message-internal.h"
+
+char dbus_py_Message_get_args_list__doc__[] = (
+"get_args_list(**kwargs) -> list\n\n"
+"Return the message's arguments. Keyword arguments control the translation\n"
+"of D-Bus types to Python:\n"
+"\n"
+":Keywords:\n"
+" `byte_arrays` : bool\n"
+" If true, convert arrays of byte (signature 'ay') into dbus.ByteArray,\n"
+" a str subclass. In practice, this is usually what you want, but\n"
+" it's off by default for consistency.\n"
+"\n"
+" If false (default), convert them into a dbus.Array of Bytes.\n"
+#ifndef PY3
+" `utf8_strings` : bool\n"
+" If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
+" If false (default), return D-Bus strings as Python unicode objects.\n"
+#endif
+"\n"
+"Most of the type mappings should be fairly obvious:\n"
+"\n"
+"=============== ===================================================\n"
+"D-Bus Python\n"
+"=============== ===================================================\n"
+"byte (y) dbus.Byte (int subclass)\n"
+"bool (b) dbus.Boolean (int subclass)\n"
+"Signature (g) dbus.Signature (str subclass)\n"
+"intNN, uintNN dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
+"double (d) dbus.Double\n"
+"string (s) dbus.String (unicode subclass)\n"
+" (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
+"Object path (o) dbus.ObjectPath (str subclass)\n"
+"dict (a{...}) dbus.Dictionary\n"
+"array (a...) dbus.Array (list subclass) containing appropriate types\n"
+"byte array (ay) dbus.ByteArray (str subclass) if byte_arrays set; or\n"
+" list of Byte\n"
+"struct ((...)) dbus.Struct (tuple subclass) of appropriate types\n"
+"variant (v) contained type, but with variant_level > 0\n"
+"=============== ===================================================\n"
+);
+
+typedef struct {
+ int byte_arrays;
+#ifndef PY3
+ int utf8_strings;
+#endif
+} Message_get_args_options;
+
+static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ long extra_variants);
+
+/* Append all the items iterated over to the given Python list object.
+ * Return 0 on success/-1 with exception on failure. */
+static int
+_message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
+ Message_get_args_options *opts)
+{
+ int ret, type;
+ while ((type = dbus_message_iter_get_arg_type(iter))
+ != DBUS_TYPE_INVALID) {
+ PyObject *item;
+ DBG("type == %d '%c'", type, type);
+
+ item = _message_iter_get_pyobject(iter, opts, 0);
+ if (!item) return -1;
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: appending to list: %p == ", (long)getpid(), item);
+ PyObject_Print(item, stderr, 0);
+ fprintf(stderr, " of type %p\n", Py_TYPE(item));
+#endif
+ ret = PyList_Append(list, item);
+ Py_CLEAR(item);
+ if (ret < 0) return -1;
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
+ PyObject_Print(list, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+ dbus_message_iter_next(iter);
+ }
+ return 0;
+}
+
+static inline PyObject *
+_message_iter_get_dict(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ PyObject *kwargs)
+{
+ DBusMessageIter entries;
+ char *sig_str = dbus_message_iter_get_signature(iter);
+ PyObject *sig;
+ PyObject *ret;
+ int status;
+
+ if (!sig_str) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(s#)", sig_str+2,
+ (Py_ssize_t)strlen(sig_str)-3);
+ dbus_free(sig_str);
+ if (!sig) {
+ return NULL;
+ }
+ status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
+ Py_CLEAR(sig);
+ if (status < 0) {
+ return NULL;
+ }
+
+ ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
+ if (!ret) {
+ return NULL;
+ }
+
+ dbus_message_iter_recurse(iter, &entries);
+ while (dbus_message_iter_get_arg_type(&entries) == DBUS_TYPE_DICT_ENTRY) {
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+ DBusMessageIter kv;
+
+ DBG("%s", "dict entry...");
+
+ dbus_message_iter_recurse(&entries, &kv);
+
+ key = _message_iter_get_pyobject(&kv, opts, 0);
+ if (!key) {
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ dbus_message_iter_next(&kv);
+
+ value = _message_iter_get_pyobject(&kv, opts, 0);
+ if (!value) {
+ Py_CLEAR(key);
+ Py_CLEAR(ret);
+ return NULL;
+ }
+
+ status = PyDict_SetItem(ret, key, value);
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+
+ if (status < 0) {
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ dbus_message_iter_next(&entries);
+ }
+
+ return ret;
+}
+
+/* Returns a new reference. */
+static PyObject *
+_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ long variant_level)
+{
+ DBusBasicValue u;
+ int type = dbus_message_iter_get_arg_type(iter);
+ PyObject *args = NULL;
+ PyObject *kwargs = NULL;
+ PyObject *ret = NULL;
+
+ /* If the variant-level is >0, prepare a dict for the kwargs.
+ * For variant wrappers optimize slightly by skipping this.
+ */
+ if (variant_level > 0 && type != DBUS_TYPE_VARIANT) {
+ PyObject *variant_level_int;
+
+ variant_level_int = NATIVEINT_FROMLONG(variant_level);
+ if (!variant_level_int) {
+ return NULL;
+ }
+ kwargs = PyDict_New();
+ if (!kwargs) {
+ Py_CLEAR(variant_level_int);
+ return NULL;
+ }
+ if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
+ variant_level_int) < 0) {
+ Py_CLEAR(variant_level_int);
+ Py_CLEAR(kwargs);
+ return NULL;
+ }
+ Py_CLEAR(variant_level_int);
+ }
+ /* From here down you need to break from the switch to exit, so the
+ * dict is freed if necessary
+ */
+
+ switch (type) {
+ PyObject *unicode;
+
+ case DBUS_TYPE_STRING:
+ DBG("%s", "found a string");
+ dbus_message_iter_get_basic(iter, &u.str);
+#ifndef PY3
+ if (opts->utf8_strings) {
+ args = Py_BuildValue("(s)", u.str);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
+ args, kwargs);
+ }
+ else {
+#endif
+ unicode = PyUnicode_DecodeUTF8(u.str, strlen(u.str), NULL);
+ if (!unicode) {
+ break;
+ }
+ args = Py_BuildValue("(N)", unicode);
+ if (!args) {
+ break;
+ }
+ ret = PyObject_Call((PyObject *)&DBusPyString_Type,
+ args, kwargs);
+#ifndef PY3
+ }
+#endif
+ break;
+
+ case DBUS_TYPE_SIGNATURE:
+ DBG("%s", "found a signature");
+ dbus_message_iter_get_basic(iter, &u.str);
+ args = Py_BuildValue("(s)", u.str);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ DBG("%s", "found an object path");
+ dbus_message_iter_get_basic(iter, &u.str);
+ args = Py_BuildValue("(s)", u.str);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ DBG("%s", "found a double");
+ dbus_message_iter_get_basic(iter, &u.dbl);
+ args = Py_BuildValue("(f)", u.dbl);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
+ break;
+
+#ifdef WITH_DBUS_FLOAT32
+ case DBUS_TYPE_FLOAT:
+ DBG("%s", "found a float");
+ /* FIXME: DBusBasicValue will need to grow a float member if
+ * float32 becomes supported */
+ dbus_message_iter_get_basic(iter, &u.f);
+ args = Py_BuildValue("(f)", (double)u.f);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
+ break;
+#endif
+
+ case DBUS_TYPE_INT16:
+ DBG("%s", "found an int16");
+ dbus_message_iter_get_basic(iter, &u.i16);
+ args = Py_BuildValue("(i)", (int)u.i16);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT16:
+ DBG("%s", "found a uint16");
+ dbus_message_iter_get_basic(iter, &u.u16);
+ args = Py_BuildValue("(i)", (int)u.u16);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_INT32:
+ DBG("%s", "found an int32");
+ dbus_message_iter_get_basic(iter, &u.i32);
+ args = Py_BuildValue("(l)", (long)u.i32);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT32:
+ DBG("%s", "found a uint32");
+ dbus_message_iter_get_basic(iter, &u.u32);
+ args = Py_BuildValue("(k)", (unsigned long)u.u32);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
+ break;
+
+#ifdef DBUS_TYPE_UNIX_FD
+ case DBUS_TYPE_UNIX_FD:
+ DBG("%s", "found an unix fd");
+ dbus_message_iter_get_basic(iter, &u.fd);
+ args = Py_BuildValue("(i)", u.fd);
+ if (args) {
+ ret = PyObject_Call((PyObject *)&DBusPyUnixFd_Type, args,
+ kwargs);
+ }
+ if (u.fd >= 0) {
+ close(u.fd);
+ }
+ break;
+#endif
+
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ case DBUS_TYPE_INT64:
+ DBG("%s", "found an int64");
+ dbus_message_iter_get_basic(iter, &u.i64);
+ args = Py_BuildValue("(L)", (PY_LONG_LONG)u.i64);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_UINT64:
+ DBG("%s", "found a uint64");
+ dbus_message_iter_get_basic(iter, &u.u64);
+ args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)u.u64);
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
+ break;
+#else
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ PyErr_SetString(PyExc_NotImplementedError,
+ "64-bit integer types are not supported on "
+ "this platform");
+ break;
+#endif
+
+ case DBUS_TYPE_BYTE:
+ DBG("%s", "found a byte");
+ dbus_message_iter_get_basic(iter, &u.byt);
+ args = Py_BuildValue("(l)", (long)u.byt);
+ if (!args)
+ break;
+ ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_BOOLEAN:
+ DBG("%s", "found a bool");
+ dbus_message_iter_get_basic(iter, &u.bool_val);
+ args = Py_BuildValue("(l)", (long)u.bool_val);
+ if (!args)
+ break;
+ ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ DBG("%s", "found an array...");
+ /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
+ Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
+ type = dbus_message_iter_get_element_type(iter);
+ if (type == DBUS_TYPE_DICT_ENTRY) {
+ DBG("%s", "no, actually it's a dict...");
+ if (!kwargs) {
+ kwargs = PyDict_New();
+ if (!kwargs) break;
+ }
+ ret = _message_iter_get_dict(iter, opts, kwargs);
+ }
+ else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
+ DBusMessageIter sub;
+ int n;
+
+ DBG("%s", "actually, a byte array...");
+ dbus_message_iter_recurse(iter, &sub);
+ dbus_message_iter_get_fixed_array(&sub,
+ (const unsigned char **)&u.str,
+ &n);
+ if (n == 0 && u.str == NULL) {
+ /* fd.o #21831: s# turns (NULL, 0) into None, but
+ * dbus_message_iter_get_fixed_array produces (NULL, 0)
+ * for an empty byte-blob... */
+ u.str = "";
+ }
+#ifdef PY3
+ args = Py_BuildValue("(y#)", u.str, (Py_ssize_t)n);
+#else
+ args = Py_BuildValue("(s#)", u.str, (Py_ssize_t)n);
+#endif
+ if (!args) break;
+ ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
+ args, kwargs);
+ }
+ else {
+ DBusMessageIter sub;
+ char *sig;
+ PyObject *sig_obj;
+ int status;
+
+ DBG("%s", "a normal array...");
+ if (!kwargs) {
+ kwargs = PyDict_New();
+ if (!kwargs) break;
+ }
+ dbus_message_iter_recurse(iter, &sub);
+ sig = dbus_message_iter_get_signature(&sub);
+ if (!sig) break;
+ sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(s)", sig);
+ dbus_free(sig);
+ if (!sig_obj) break;
+ status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
+ Py_CLEAR(sig_obj);
+ if (status < 0) break;
+ ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
+ dbus_py_empty_tuple, kwargs);
+ if (!ret) break;
+ if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
+ Py_CLEAR(ret);
+ }
+ }
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ {
+ DBusMessageIter sub;
+ PyObject *list = PyList_New(0);
+ PyObject *tuple;
+
+ DBG("%s", "found a struct...");
+ if (!list) break;
+ dbus_message_iter_recurse(iter, &sub);
+ if (_message_iter_append_all_to_list(&sub, list, opts) < 0) {
+ Py_CLEAR(list);
+ break;
+ }
+ tuple = Py_BuildValue("(O)", list);
+ if (tuple) {
+ ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
+ }
+ else {
+ ret = NULL;
+ }
+ /* whether successful or not, we take the same action: */
+ Py_CLEAR(list);
+ Py_CLEAR(tuple);
+ }
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ {
+ DBusMessageIter sub;
+
+ DBG("%s", "found a variant...");
+ dbus_message_iter_recurse(iter, &sub);
+ ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
+ }
+ break;
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
+ "message", type);
+ }
+
+ Py_CLEAR(args);
+ Py_CLEAR(kwargs);
+ return ret;
+}
+
+PyObject *
+dbus_py_Message_get_args_list(Message *self, PyObject *args, PyObject *kwargs)
+{
+#ifdef PY3
+ Message_get_args_options opts = { 0 };
+ static char *argnames[] = { "byte_arrays", NULL };
+#else
+ Message_get_args_options opts = { 0, 0 };
+ static char *argnames[] = { "byte_arrays", "utf8_strings", NULL };
+#endif
+ PyObject *list;
+ DBusMessageIter iter;
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
+ (long)getpid());
+ PyObject_Print(args, stderr, 0);
+ if (kwargs) {
+ fprintf(stderr, ", **");
+ PyObject_Print(kwargs, stderr, 0);
+ }
+ fprintf(stderr, ")\n");
+#endif
+
+ if (PyTuple_Size(args) != 0) {
+ PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
+ "arguments");
+ return NULL;
+ }
+#ifdef PY3
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:get_args_list",
+ argnames,
+ &(opts.byte_arrays))) return NULL;
+#else
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
+ argnames,
+ &(opts.byte_arrays),
+ &(opts.utf8_strings))) return NULL;
+#endif
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+
+ list = PyList_New(0);
+ if (!list) return NULL;
+
+ /* Iterate over args, if any, appending to list */
+ if (dbus_message_iter_init(self->msg, &iter)) {
+ if (_message_iter_append_all_to_list(&iter, list, &opts) < 0) {
+ Py_CLEAR(list);
+ DBG_EXC("%s", "Message_get_args: appending all to list failed:");
+ return NULL;
+ }
+ }
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
+ PyObject_Print(list, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ return list;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/message-internal.h b/dbus_bindings/message-internal.h
new file mode 100644
index 0000000..dfa78e0
--- /dev/null
+++ b/dbus_bindings/message-internal.h
@@ -0,0 +1,49 @@
+/* D-Bus message: implementation internals
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DBUS_BINDINGS_MESSAGE_INTERNAL_H
+#define DBUS_BINDINGS_MESSAGE_INTERNAL_H
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+
+typedef struct {
+ PyObject_HEAD
+ DBusMessage *msg;
+} Message;
+
+extern char dbus_py_Message_append__doc__[];
+extern PyObject *dbus_py_Message_append(Message *, PyObject *, PyObject *);
+extern char dbus_py_Message_guess_signature__doc__[];
+extern PyObject *dbus_py_Message_guess_signature(PyObject *, PyObject *);
+extern char dbus_py_Message_get_args_list__doc__[];
+extern PyObject *dbus_py_Message_get_args_list(Message *,
+ PyObject *,
+ PyObject *);
+
+extern PyObject *DBusPy_RaiseUnusableMessage(void);
+
+#endif
diff --git a/dbus_bindings/message.c b/dbus_bindings/message.c
new file mode 100644
index 0000000..ded8fe1
--- /dev/null
+++ b/dbus_bindings/message.c
@@ -0,0 +1,1110 @@
+/* Implementation of D-Bus Message and subclasses (but see message-get-args.h
+ * and message-append.h for unserialization and serialization code).
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+#include "message-internal.h"
+
+static PyTypeObject MessageType, SignalMessageType, ErrorMessageType;
+static PyTypeObject MethodReturnMessageType, MethodCallMessageType;
+
+static inline int Message_Check(PyObject *o)
+{
+ return (Py_TYPE(o) == &MessageType)
+ || PyObject_IsInstance(o, (PyObject *)&MessageType);
+}
+
+PyObject *
+DBusPy_RaiseUnusableMessage(void)
+{
+ DBusPyException_SetString("Message object is uninitialized, or has become "
+ "unusable due to error while appending "
+ "arguments");
+ return NULL;
+}
+
+PyDoc_STRVAR(Message_tp_doc,
+"A message to be sent or received over a D-Bus Connection.\n");
+
+static void Message_tp_dealloc(Message *self)
+{
+ if (self->msg) {
+ dbus_message_unref(self->msg);
+ }
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyObject *
+Message_tp_new(PyTypeObject *type,
+ PyObject *args UNUSED,
+ PyObject *kwargs UNUSED)
+{
+ Message *self;
+
+ self = (Message *)type->tp_alloc(type, 0);
+ if (!self) return NULL;
+ self->msg = NULL;
+ return (PyObject *)self;
+}
+
+static PyObject *
+MethodCallMessage_tp_repr(PyObject *self)
+{
+ DBusMessage *msg = ((Message *)self)->msg;
+ const char *destination = dbus_message_get_destination(msg);
+ const char *path = dbus_message_get_path(msg);
+ const char *interface = dbus_message_get_interface(msg);
+ const char *member = dbus_message_get_member(msg);
+
+ if (!path)
+ path = "n/a";
+ if (!interface)
+ interface = "n/a";
+ if (!member)
+ member = "n/a";
+ if (!destination)
+ destination = "n/a";
+
+ return PyUnicode_FromFormat(
+ "<%s path: %s, iface: %s, member: %s dest: %s>",
+ Py_TYPE(self)->tp_name,
+ path, interface, member, destination);
+}
+
+PyDoc_STRVAR(MethodCallMessage_tp_doc, "A method-call message.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.lowlevel.MethodCallMessage(destination: str or None, path: str,\n"
+" interface: str or None, method: str)\n"
+"\n"
+"``destination`` is the destination bus name, or None to send the\n"
+"message directly to the peer (usually the bus daemon).\n"
+"\n"
+"``path`` is the object-path of the object whose method is to be called.\n"
+"\n"
+"``interface`` is the interface qualifying the method name, or None to omit\n"
+"the interface from the message header.\n"
+"\n"
+"``method`` is the method name (member name).\n"
+);
+
+static int
+MethodCallMessage_tp_init(Message *self, PyObject *args, PyObject *kwargs)
+{
+ const char *destination, *path, *interface, *method;
+ static char *kwlist[] = {"destination", "path", "interface", "method", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zszs:__init__", kwlist,
+ &destination, &path, &interface,
+ &method)) {
+ return -1;
+ }
+ if (destination && !dbus_py_validate_bus_name(destination, 1, 1)) return -1;
+ if (!dbus_py_validate_object_path(path)) return -1;
+ if (interface && !dbus_py_validate_interface_name(interface)) return -1;
+ if (!dbus_py_validate_member_name(method)) return -1;
+ if (self->msg) {
+ dbus_message_unref(self->msg);
+ self->msg = NULL;
+ }
+ self->msg = dbus_message_new_method_call(destination, path, interface,
+ method);
+ if (!self->msg) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+PyDoc_STRVAR(MethodReturnMessage_tp_doc, "A method-return message.\n\n"
+"Constructor::\n\n"
+" dbus.lowlevel.MethodReturnMessage(method_call: MethodCallMessage)\n");
+
+static int
+MethodReturnMessage_tp_init(Message *self, PyObject *args, PyObject *kwargs)
+{
+ Message *other;
+ static char *kwlist[] = {"method_call", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:__init__", kwlist,
+ &MessageType, &other)) {
+ return -1;
+ }
+ if (self->msg) {
+ dbus_message_unref(self->msg);
+ self->msg = NULL;
+ }
+ self->msg = dbus_message_new_method_return(other->msg);
+ if (!self->msg) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+PyDoc_STRVAR(SignalMessage_tp_doc, "A signal message.\n\n"
+"Constructor::\n\n"
+" dbus.lowlevel.SignalMessage(path: str, interface: str, method: str)\n");
+static int
+SignalMessage_tp_init(Message *self, PyObject *args, PyObject *kwargs)
+{
+ const char *path, *interface, *name;
+ static char *kwlist[] = {"path", "interface", "name", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss:__init__", kwlist,
+ &path, &interface, &name)) {
+ return -1;
+ }
+ if (!dbus_py_validate_object_path(path)) return -1;
+ if (!dbus_py_validate_interface_name(interface)) return -1;
+ if (!dbus_py_validate_member_name(name)) return -1;
+ if (self->msg) {
+ dbus_message_unref(self->msg);
+ self->msg = NULL;
+ }
+ self->msg = dbus_message_new_signal(path, interface, name);
+ if (!self->msg) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *
+SignalMessage_tp_repr(PyObject *self)
+{
+ DBusMessage *msg = ((Message *)self)->msg;
+ const char *path = dbus_message_get_path(msg);
+ const char *interface = dbus_message_get_interface(msg);
+ const char *member = dbus_message_get_member(msg);
+ const char *destination = dbus_message_get_destination(msg);
+
+ if (!path)
+ path = "n/a";
+ if (!interface)
+ interface = "n/a";
+ if (!member)
+ member = "n/a";
+ if (!destination)
+ destination = "(broadcast)";
+
+ return PyUnicode_FromFormat("<%s path: %s, iface: %s, member: %s, dest: %s>",
+ Py_TYPE(self)->tp_name,
+ path, interface, member, destination);
+}
+
+PyDoc_STRVAR(ErrorMessage_tp_doc, "An error message.\n\n"
+"Constructor::\n\n"
+" dbus.lowlevel.ErrorMessage(reply_to: Message, error_name: str,\n"
+" error_message: str or None)\n");
+static int
+ErrorMessage_tp_init(Message *self, PyObject *args, PyObject *kwargs)
+{
+ Message *reply_to;
+ const char *error_name, *error_message;
+ static char *kwlist[] = {"reply_to", "error_name", "error_message", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!sz:__init__", kwlist,
+ &MessageType, &reply_to, &error_name,
+ &error_message)) {
+ return -1;
+ }
+ if (!dbus_py_validate_error_name(error_name)) return -1;
+ if (self->msg) {
+ dbus_message_unref(self->msg);
+ self->msg = NULL;
+ }
+ self->msg = dbus_message_new_error(reply_to->msg, error_name, error_message);
+ if (!self->msg) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+DBusMessage *
+DBusPyMessage_BorrowDBusMessage(PyObject *msg)
+{
+ if (!Message_Check(msg)) {
+ PyErr_SetString(PyExc_TypeError,
+ "A dbus.lowlevel.Message instance is required");
+ return NULL;
+ }
+ if (!((Message *)msg)->msg) {
+ DBusPy_RaiseUnusableMessage();
+ return NULL;
+ }
+ return ((Message *)msg)->msg;
+}
+
+PyObject *
+DBusPyMessage_ConsumeDBusMessage(DBusMessage *msg)
+{
+ PyTypeObject *type;
+ Message *self;
+
+ switch (dbus_message_get_type(msg)) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ type = &MethodCallMessageType;
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ type = &MethodReturnMessageType;
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ type = &ErrorMessageType;
+ break;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ type = &SignalMessageType;
+ break;
+ default:
+ type = &MessageType;
+ }
+
+ self = (Message *)(type->tp_new) (type, dbus_py_empty_tuple, NULL);
+ if (!self) {
+ dbus_message_unref(msg);
+ return NULL;
+ }
+ self->msg = msg;
+ return (PyObject *)self;
+}
+
+PyDoc_STRVAR(Message_copy__doc__,
+"message.copy() -> Message (or subclass)\n"
+"Deep-copy the message, resetting the serial number to zero.\n");
+static PyObject *
+Message_copy(Message *self, PyObject *args UNUSED)
+{
+ DBusMessage *msg;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ msg = dbus_message_copy(self->msg);
+ if (!msg) return PyErr_NoMemory();
+ return DBusPyMessage_ConsumeDBusMessage(msg);
+}
+
+PyDoc_STRVAR(Message_get_auto_start__doc__,
+"message.get_auto_start() -> bool\n"
+"Return true if this message will cause an owner for the destination name\n"
+"to be auto-started.\n");
+static PyObject *
+Message_get_auto_start(Message *self, PyObject *unused UNUSED)
+{
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_get_auto_start(self->msg));
+}
+
+PyDoc_STRVAR(Message_set_auto_start__doc__,
+"message.set_auto_start(bool) -> None\n"
+"Set whether this message will cause an owner for the destination name\n"
+"to be auto-started.\n");
+static PyObject *
+Message_set_auto_start(Message *self, PyObject *args)
+{
+ int value;
+ if (!PyArg_ParseTuple(args, "i", &value)) return NULL;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ dbus_message_set_auto_start(self->msg, value ? TRUE : FALSE);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(Message_get_no_reply__doc__,
+"message.get_no_reply() -> bool\n"
+"Return true if this message need not be replied to.\n");
+static PyObject *
+Message_get_no_reply(Message *self, PyObject *unused UNUSED)
+{
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_get_no_reply(self->msg));
+}
+
+PyDoc_STRVAR(Message_set_no_reply__doc__,
+"message.set_no_reply(bool) -> None\n"
+"Set whether no reply to this message is required.\n");
+static PyObject *
+Message_set_no_reply(Message *self, PyObject *args)
+{
+ int value;
+ if (!PyArg_ParseTuple(args, "i", &value)) return NULL;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ dbus_message_set_no_reply(self->msg, value ? TRUE : FALSE);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_reply_serial__doc__,
+"message.get_reply_serial() -> long\n"
+"Returns the serial that the message is a reply to or 0 if none.\n");
+static PyObject *
+Message_get_reply_serial(Message *self, PyObject *unused UNUSED)
+{
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyLong_FromUnsignedLong(dbus_message_get_reply_serial(self->msg));
+}
+
+PyDoc_STRVAR(Message_set_reply_serial__doc__,
+"message.set_reply_serial(bool) -> None\n"
+"Set the serial that this message is a reply to.\n");
+static PyObject *
+Message_set_reply_serial(Message *self, PyObject *args)
+{
+ dbus_uint32_t value;
+
+ if (!PyArg_ParseTuple(args, "k", &value)) return NULL;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_message_set_reply_serial(self->msg, value)) {
+ return PyErr_NoMemory();
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyDoc_STRVAR(Message_get_type__doc__,
+"message.get_type() -> int\n\n"
+"Returns the type of the message.\n");
+static PyObject *
+Message_get_type(Message *self, PyObject *unused UNUSED)
+{
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return NATIVEINT_FROMLONG(dbus_message_get_type(self->msg));
+}
+
+PyDoc_STRVAR(Message_get_serial__doc__,
+"message.get_serial() -> long\n"
+"Returns the serial of a message or 0 if none has been specified.\n"
+"\n"
+"The message's serial number is provided by the application sending the\n"
+"message and is used to identify replies to this message. All messages\n"
+"received on a connection will have a serial, but messages you haven't\n"
+"sent yet may return 0.\n");
+static PyObject *
+Message_get_serial(Message *self, PyObject *unused UNUSED)
+{
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyLong_FromUnsignedLong(dbus_message_get_serial(self->msg));
+}
+
+PyDoc_STRVAR(Message_is_method_call__doc__,
+"is_method_call(interface: str, member: str) -> bool");
+static PyObject *
+Message_is_method_call(Message *self, PyObject *args)
+{
+ const char *interface, *method;
+
+ if (!PyArg_ParseTuple(args, "ss:is_method_call", &interface, &method)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_is_method_call(self->msg, interface,
+ method));
+}
+
+PyDoc_STRVAR(Message_is_error__doc__,
+"is_error(error: str) -> bool");
+static PyObject *
+Message_is_error(Message *self, PyObject *args)
+{
+ const char *error_name;
+
+ if (!PyArg_ParseTuple(args, "s:is_error", &error_name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_is_error(self->msg, error_name));
+}
+
+PyDoc_STRVAR(Message_is_signal__doc__,
+"is_signal(interface: str, member: str) -> bool");
+static PyObject *
+Message_is_signal(Message *self, PyObject *args)
+{
+ const char *interface, *signal_name;
+
+ if (!PyArg_ParseTuple(args, "ss:is_signal", &interface, &signal_name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_is_signal(self->msg, interface,
+ signal_name));
+}
+
+PyDoc_STRVAR(Message_get_member__doc__,
+"get_member() -> str or None");
+static PyObject *
+Message_get_member(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_member(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return NATIVESTR_FROMSTR(c_str);
+}
+
+PyDoc_STRVAR(Message_has_member__doc__,
+"has_member(name: str or None) -> bool");
+static PyObject *
+Message_has_member(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:has_member", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_member(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_set_member__doc__,
+"set_member(unique_name: str or None)");
+static PyObject *
+Message_set_member(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_member", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_py_validate_member_name(name)) return NULL;
+ if (!dbus_message_set_member(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_path__doc__,
+"get_path() -> ObjectPath or None\n\n"
+"Return the message's destination object path (if it's a method call) or\n"
+"source object path (if it's a method reply or a signal) or None (if it\n"
+"has no path).\n");
+static PyObject *
+Message_get_path(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_path(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyObject_CallFunction((PyObject *)&DBusPyObjectPath_Type, "(s)", c_str);
+}
+
+PyDoc_STRVAR(Message_get_path_decomposed__doc__,
+"get_path_decomposed() -> list of str, or None\n\n"
+"Return a list of path components (e.g. /foo/bar -> ['foo','bar'], / -> [])\n"
+"or None if the message has no associated path.\n");
+static PyObject *
+Message_get_path_decomposed(Message *self, PyObject *unused UNUSED)
+{
+ char **paths, **ptr;
+ PyObject *ret = PyList_New(0);
+
+ if (!ret) return NULL;
+ if (!self->msg) {
+ Py_CLEAR(ret);
+ return DBusPy_RaiseUnusableMessage();
+ }
+ if (!dbus_message_get_path_decomposed(self->msg, &paths)) {
+ Py_CLEAR(ret);
+ return PyErr_NoMemory();
+ }
+ if (!paths) {
+ Py_CLEAR(ret);
+ Py_RETURN_NONE;
+ }
+ for (ptr = paths; *ptr; ptr++) {
+ PyObject *str = NATIVESTR_FROMSTR(*ptr);
+
+ if (!str) {
+ Py_CLEAR(ret);
+ break;
+ }
+ if (PyList_Append(ret, str) < 0) {
+ Py_CLEAR(ret);
+ break;
+ }
+ Py_CLEAR(str);
+ str = NULL;
+ }
+ dbus_free_string_array(paths);
+ return ret;
+}
+
+PyDoc_STRVAR(Message_has_path__doc__,
+"has_path(name: str or None) -> bool");
+static PyObject *
+Message_has_path(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:has_path", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_path(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_set_path__doc__,
+"set_path(name: str or None)");
+static PyObject *
+Message_set_path(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_path", &name)) return NULL;
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_message_has_path(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_signature__doc__,
+"get_signature() -> Signature or None");
+static PyObject *
+Message_get_signature(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_signature(self->msg);
+ if (!c_str) {
+ return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
+ }
+ return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", c_str);
+}
+
+PyDoc_STRVAR(Message_has_signature__doc__,
+"has_signature(signature: str) -> bool");
+static PyObject *
+Message_has_signature(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:has_signature", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_signature(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_get_sender__doc__,
+"get_sender() -> str or None\n\n"
+"Return the message's sender unique name, or None if none.\n");
+static PyObject *
+Message_get_sender(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_sender(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return NATIVESTR_FROMSTR(c_str);
+}
+
+PyDoc_STRVAR(Message_has_sender__doc__,
+"has_sender(unique_name: str) -> bool");
+static PyObject *
+Message_has_sender(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:has_sender", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_sender(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_set_sender__doc__,
+"set_sender(unique_name: str or None)");
+static PyObject *
+Message_set_sender(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_sender", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_py_validate_bus_name(name, 1, 1)) return NULL;
+ if (!dbus_message_set_sender(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_destination__doc__,
+"get_destination() -> str or None\n\n"
+"Return the message's destination bus name, or None if none.\n");
+static PyObject *
+Message_get_destination(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_destination(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return NATIVESTR_FROMSTR(c_str);
+}
+
+PyDoc_STRVAR(Message_has_destination__doc__,
+"has_destination(bus_name: str) -> bool");
+static PyObject *
+Message_has_destination(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:has_destination", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_destination(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_set_destination__doc__,
+"set_destination(bus_name: str or None)");
+static PyObject *
+Message_set_destination(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_destination", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_py_validate_bus_name(name, 1, 1)) return NULL;
+ if (!dbus_message_set_destination(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_interface__doc__,
+"get_interface() -> str or None");
+static PyObject *
+Message_get_interface(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_interface(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return NATIVESTR_FROMSTR(c_str);
+}
+
+PyDoc_STRVAR(Message_has_interface__doc__,
+"has_interface(interface: str or None) -> bool");
+static PyObject *
+Message_has_interface(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:has_interface", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ return PyBool_FromLong(dbus_message_has_interface(self->msg, name));
+}
+
+PyDoc_STRVAR(Message_set_interface__doc__,
+"set_interface(name: str or None)");
+static PyObject *
+Message_set_interface(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_interface", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_py_validate_interface_name(name)) return NULL;
+ if (!dbus_message_set_interface(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Message_get_error_name__doc__,
+"get_error_name() -> str or None");
+static PyObject *
+Message_get_error_name(Message *self, PyObject *unused UNUSED)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ c_str = dbus_message_get_error_name(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return NATIVESTR_FROMSTR(c_str);
+}
+
+PyDoc_STRVAR(Message_set_error_name__doc__,
+"set_error_name(name: str or None)");
+static PyObject *
+Message_set_error_name(Message *self, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "z:set_error_name", &name)) {
+ return NULL;
+ }
+ if (!self->msg) return DBusPy_RaiseUnusableMessage();
+ if (!dbus_py_validate_error_name(name)) return NULL;
+ if (!dbus_message_set_error_name(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef Message_tp_methods[] = {
+ {"copy", (PyCFunction)Message_copy,
+ METH_NOARGS, Message_copy__doc__},
+ {"is_method_call", (PyCFunction)Message_is_method_call,
+ METH_VARARGS, Message_is_method_call__doc__},
+ {"is_signal", (PyCFunction)Message_is_signal,
+ METH_VARARGS, Message_is_signal__doc__},
+ {"is_error", (PyCFunction)Message_is_error,
+ METH_VARARGS, Message_is_error__doc__},
+
+ {"get_args_list", (PyCFunction)dbus_py_Message_get_args_list,
+ METH_VARARGS|METH_KEYWORDS, dbus_py_Message_get_args_list__doc__},
+ {"guess_signature", (PyCFunction)dbus_py_Message_guess_signature,
+ METH_VARARGS|METH_STATIC, dbus_py_Message_guess_signature__doc__},
+ {"append", (PyCFunction)dbus_py_Message_append,
+ METH_VARARGS|METH_KEYWORDS, dbus_py_Message_append__doc__},
+
+ {"get_auto_start", (PyCFunction)Message_get_auto_start,
+ METH_NOARGS, Message_get_auto_start__doc__},
+ {"set_auto_start", (PyCFunction)Message_set_auto_start,
+ METH_VARARGS, Message_set_auto_start__doc__},
+ {"get_destination", (PyCFunction)Message_get_destination,
+ METH_NOARGS, Message_get_destination__doc__},
+ {"set_destination", (PyCFunction)Message_set_destination,
+ METH_VARARGS, Message_set_destination__doc__},
+ {"has_destination", (PyCFunction)Message_has_destination,
+ METH_VARARGS, Message_has_destination__doc__},
+ {"get_error_name", (PyCFunction)Message_get_error_name,
+ METH_NOARGS, Message_get_error_name__doc__},
+ {"set_error_name", (PyCFunction)Message_set_error_name,
+ METH_VARARGS, Message_set_error_name__doc__},
+ {"get_interface", (PyCFunction)Message_get_interface,
+ METH_NOARGS, Message_get_interface__doc__},
+ {"set_interface", (PyCFunction)Message_set_interface,
+ METH_VARARGS, Message_set_interface__doc__},
+ {"has_interface", (PyCFunction)Message_has_interface,
+ METH_VARARGS, Message_has_interface__doc__},
+ {"get_member", (PyCFunction)Message_get_member,
+ METH_NOARGS, Message_get_member__doc__},
+ {"set_member", (PyCFunction)Message_set_member,
+ METH_VARARGS, Message_set_member__doc__},
+ {"has_member", (PyCFunction)Message_has_member,
+ METH_VARARGS, Message_has_member__doc__},
+ {"get_path", (PyCFunction)Message_get_path,
+ METH_NOARGS, Message_get_path__doc__},
+ {"get_path_decomposed", (PyCFunction)Message_get_path_decomposed,
+ METH_NOARGS, Message_get_path_decomposed__doc__},
+ {"set_path", (PyCFunction)Message_set_path,
+ METH_VARARGS, Message_set_path__doc__},
+ {"has_path", (PyCFunction)Message_has_path,
+ METH_VARARGS, Message_has_path__doc__},
+ {"get_no_reply", (PyCFunction)Message_get_no_reply,
+ METH_NOARGS, Message_get_no_reply__doc__},
+ {"set_no_reply", (PyCFunction)Message_set_no_reply,
+ METH_VARARGS, Message_set_no_reply__doc__},
+ {"get_reply_serial", (PyCFunction)Message_get_reply_serial,
+ METH_NOARGS, Message_get_reply_serial__doc__},
+ {"set_reply_serial", (PyCFunction)Message_set_reply_serial,
+ METH_VARARGS, Message_set_reply_serial__doc__},
+ {"get_sender", (PyCFunction)Message_get_sender,
+ METH_NOARGS, Message_get_sender__doc__},
+ {"set_sender", (PyCFunction)Message_set_sender,
+ METH_VARARGS, Message_set_sender__doc__},
+ {"has_sender", (PyCFunction)Message_has_sender,
+ METH_VARARGS, Message_has_sender__doc__},
+ {"get_serial", (PyCFunction)Message_get_serial,
+ METH_NOARGS, Message_get_serial__doc__},
+ {"get_signature", (PyCFunction)Message_get_signature,
+ METH_NOARGS, Message_get_signature__doc__},
+ {"has_signature", (PyCFunction)Message_has_signature,
+ METH_VARARGS, Message_has_signature__doc__},
+ {"get_type", (PyCFunction)Message_get_type,
+ METH_NOARGS, Message_get_type__doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject MessageType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.lowlevel.Message", /*tp_name*/
+ sizeof(Message), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Message_tp_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Message_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Message_tp_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Message_tp_new, /* tp_new */
+};
+
+static PyTypeObject MethodCallMessageType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.lowlevel.MethodCallMessage", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ MethodCallMessage_tp_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ MethodCallMessage_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&MessageType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)MethodCallMessage_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static PyTypeObject MethodReturnMessageType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.lowlevel.MethodReturnMessage", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ MethodReturnMessage_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&MessageType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)MethodReturnMessage_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static PyTypeObject SignalMessageType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.lowlevel.SignalMessage", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ SignalMessage_tp_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ SignalMessage_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&MessageType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SignalMessage_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static PyTypeObject ErrorMessageType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.lowlevel.ErrorMessage", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ ErrorMessage_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&MessageType), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ErrorMessage_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_message_types(void)
+{
+ if (PyType_Ready(&MessageType) < 0) return 0;
+
+ MethodCallMessageType.tp_base = &MessageType;
+ if (PyType_Ready(&MethodCallMessageType) < 0) return 0;
+
+ MethodReturnMessageType.tp_base = &MessageType;
+ if (PyType_Ready(&MethodReturnMessageType) < 0) return 0;
+
+ SignalMessageType.tp_base = &MessageType;
+ if (PyType_Ready(&SignalMessageType) < 0) return 0;
+
+ ErrorMessageType.tp_base = &MessageType;
+ if (PyType_Ready(&ErrorMessageType) < 0) return 0;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_message_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&MessageType);
+ Py_INCREF (&MethodCallMessageType);
+ Py_INCREF (&MethodReturnMessageType);
+ Py_INCREF (&ErrorMessageType);
+ Py_INCREF (&SignalMessageType);
+
+ if (PyModule_AddObject(this_module, "Message",
+ (PyObject *)&MessageType) < 0) return 0;
+
+ if (PyModule_AddObject(this_module, "MethodCallMessage",
+ (PyObject *)&MethodCallMessageType) < 0) return 0;
+
+ if (PyModule_AddObject(this_module, "MethodReturnMessage",
+ (PyObject *)&MethodReturnMessageType) < 0) return 0;
+
+ if (PyModule_AddObject(this_module, "ErrorMessage",
+ (PyObject *)&ErrorMessageType) < 0) return 0;
+
+ if (PyModule_AddObject(this_module, "SignalMessage",
+ (PyObject *)&SignalMessageType) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/module.c b/dbus_bindings/module.c
new file mode 100644
index 0000000..5b8851c
--- /dev/null
+++ b/dbus_bindings/module.c
@@ -0,0 +1,432 @@
+/* Main module source for the _dbus_bindings extension.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+PyDoc_STRVAR(module_doc,
+"Low-level Python bindings for libdbus. Don't use this module directly -\n"
+"the public API is provided by the `dbus`, `dbus.service`, `dbus.mainloop`\n"
+"and `dbus.mainloop.glib` modules, with a lower-level API provided by the\n"
+"`dbus.lowlevel` module.\n"
+);
+
+/* Global functions - validation wrappers ===========================*/
+
+PyDoc_STRVAR(validate_bus_name__doc__,
+"validate_bus_name(name, allow_unique=True, allow_well_known=True)\n"
+"\n"
+"Raise ValueError if the argument is not a valid bus name.\n"
+"\n"
+"By default both unique and well-known names are accepted.\n"
+"\n"
+":Parameters:\n"
+" `name` : str\n"
+" The name to be validated\n"
+" `allow_unique` : bool\n"
+" If False, unique names of the form :1.123 will be rejected\n"
+" `allow_well_known` : bool\n"
+" If False, well-known names of the form com.example.Foo\n"
+" will be rejected\n"
+":Since: 0.80\n"
+);
+
+static PyObject *
+validate_bus_name(PyObject *unused UNUSED, PyObject *args, PyObject *kwargs)
+{
+ const char *name;
+ int allow_unique = 1;
+ int allow_well_known = 1;
+ static char *argnames[] = { "name", "allow_unique", "allow_well_known",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "s|ii:validate_bus_name", argnames,
+ &name, &allow_unique,
+ &allow_well_known)) {
+ return NULL;
+ }
+ if (!dbus_py_validate_bus_name(name, !!allow_unique, !!allow_well_known)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(validate_member_name__doc__,
+"validate_member_name(name)\n"
+"\n"
+"Raise ValueError if the argument is not a valid member (signal or method) "
+"name.\n"
+"\n"
+":Since: 0.80\n"
+);
+
+static PyObject *
+validate_member_name(PyObject *unused UNUSED, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:validate_member_name", &name)) {
+ return NULL;
+ }
+ if (!dbus_py_validate_member_name(name)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(validate_interface_name__doc__,
+"validate_interface_name(name)\n\n"
+"Raise ValueError if the given string is not a valid interface name.\n"
+"\n"
+":Since: 0.80\n"
+);
+
+PyDoc_STRVAR(validate_error_name__doc__,
+"validate_error_name(name)\n\n"
+"Raise ValueError if the given string is not a valid error name.\n"
+"\n"
+":Since: 0.80\n"
+);
+
+static PyObject *
+validate_interface_name(PyObject *unused UNUSED, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:validate_interface_name", &name)) {
+ return NULL;
+ }
+ if (!dbus_py_validate_interface_name(name)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(validate_object_path__doc__,
+"validate_object_path(name)\n\n"
+"Raise ValueError if the given string is not a valid object path.\n"
+"\n"
+":Since: 0.80\n"
+);
+
+static PyObject *
+validate_object_path(PyObject *unused UNUSED, PyObject *args)
+{
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "s:validate_object_path", &name)) {
+ return NULL;
+ }
+ if (!dbus_py_validate_object_path(name)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/* Global functions - main loop =====================================*/
+
+/* The main loop if none is passed to the constructor */
+static PyObject *default_main_loop = NULL;
+
+/* Return a new reference to the default main loop */
+PyObject *
+dbus_py_get_default_main_loop(void)
+{
+ if (!default_main_loop) {
+ Py_RETURN_NONE;
+ }
+ Py_INCREF(default_main_loop);
+ return default_main_loop;
+}
+
+PyDoc_STRVAR(get_default_main_loop__doc__,
+"get_default_main_loop() -> object\n\n"
+"Return the global default dbus-python main loop wrapper, which is used\n"
+"when no main loop wrapper is passed to the Connection constructor.\n"
+"\n"
+"If None, there is no default and you should always pass the mainloop\n"
+"parameter to the constructor - if you don't, then asynchronous calls,\n"
+"connecting to signals and exporting objects will raise an exception.\n"
+"There is no default until set_default_main_loop is called.\n");
+static PyObject *
+get_default_main_loop(PyObject *always_null UNUSED,
+ PyObject *no_args UNUSED)
+{
+ return dbus_py_get_default_main_loop();
+}
+
+PyDoc_STRVAR(set_default_main_loop__doc__,
+"set_default_main_loop(object)\n\n"
+"Change the global default dbus-python main loop wrapper, which is used\n"
+"when no main loop wrapper is passed to the Connection constructor.\n"
+"\n"
+"If None, return to the initial situation: there is no default, and you\n"
+"must always pass the mainloop parameter to the constructor.\n"
+"\n"
+"Two types of main loop wrapper are planned in dbus-python.\n"
+"Native main-loop wrappers are instances of `dbus.mainloop.NativeMainLoop`\n"
+"supplied by extension modules like `dbus.mainloop.glib`: they have no\n"
+"Python API, but connect themselves to ``libdbus`` using native code.\n"
+
+"Python main-loop wrappers are not yet implemented. They will be objects\n"
+"supporting the interface defined by `dbus.mainloop.MainLoop`, with an\n"
+"API entirely based on Python methods.\n"
+"\n"
+);
+static PyObject *
+set_default_main_loop(PyObject *always_null UNUSED,
+ PyObject *args)
+{
+ PyObject *new_loop, *old_loop;
+
+ if (!PyArg_ParseTuple(args, "O", &new_loop)) {
+ return NULL;
+ }
+ if (!dbus_py_check_mainloop_sanity(new_loop)) {
+ return NULL;
+ }
+ old_loop = default_main_loop;
+ Py_INCREF(new_loop);
+ default_main_loop = new_loop;
+ Py_CLEAR(old_loop);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef module_functions[] = {
+#define ENTRY(name,flags) {#name, (PyCFunction)name, flags, name##__doc__}
+ ENTRY(validate_interface_name, METH_VARARGS),
+ ENTRY(validate_member_name, METH_VARARGS),
+ ENTRY(validate_bus_name, METH_VARARGS|METH_KEYWORDS),
+ ENTRY(validate_object_path, METH_VARARGS),
+ ENTRY(set_default_main_loop, METH_VARARGS),
+ ENTRY(get_default_main_loop, METH_NOARGS),
+ /* validate_error_name is just implemented as validate_interface_name */
+ {"validate_error_name", validate_interface_name,
+ METH_VARARGS, validate_error_name__doc__},
+#undef ENTRY
+ {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC
+#ifdef PY3
+PyInit__dbus_bindings(void)
+#else
+init_dbus_bindings(void)
+#endif
+{
+ PyObject *this_module = NULL, *c_api;
+ static const int API_count = DBUS_BINDINGS_API_COUNT;
+ static _dbus_py_func_ptr dbus_bindings_API[DBUS_BINDINGS_API_COUNT];
+
+#ifdef PY3
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "_dbus_bindings", /* m_name */
+ module_doc, /* m_doc */
+ -1, /* m_size */
+ module_functions, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL /* m_free */
+ };
+#endif
+
+ dbus_bindings_API[0] = (_dbus_py_func_ptr)&API_count;
+ dbus_bindings_API[1] = (_dbus_py_func_ptr)DBusPyConnection_BorrowDBusConnection;
+ dbus_bindings_API[2] = (_dbus_py_func_ptr)DBusPyNativeMainLoop_New4;
+
+ default_main_loop = NULL;
+
+ if (!dbus_py_init_generic()) goto init_error;
+ if (!dbus_py_init_abstract()) goto init_error;
+ if (!dbus_py_init_signature()) goto init_error;
+ if (!dbus_py_init_int_types()) goto init_error;
+ if (!dbus_py_init_unixfd_type()) goto init_error;
+ if (!dbus_py_init_string_types()) goto init_error;
+ if (!dbus_py_init_float_types()) goto init_error;
+ if (!dbus_py_init_container_types()) goto init_error;
+ if (!dbus_py_init_byte_types()) goto init_error;
+ if (!dbus_py_init_message_types()) goto init_error;
+ if (!dbus_py_init_pending_call()) goto init_error;
+ if (!dbus_py_init_mainloop()) goto init_error;
+ if (!dbus_py_init_libdbus_conn_types()) goto init_error;
+ if (!dbus_py_init_conn_types()) goto init_error;
+ if (!dbus_py_init_server_types()) goto init_error;
+
+#ifdef PY3
+ this_module = PyModule_Create(&moduledef);
+#else
+ this_module = Py_InitModule3("_dbus_bindings",
+ module_functions, module_doc);
+#endif
+ if (!this_module) goto init_error;
+
+ if (!dbus_py_insert_abstract_types(this_module)) goto init_error;
+ if (!dbus_py_insert_signature(this_module)) goto init_error;
+ if (!dbus_py_insert_int_types(this_module)) goto init_error;
+ if (!dbus_py_insert_unixfd_type(this_module)) goto init_error;
+ if (!dbus_py_insert_string_types(this_module)) goto init_error;
+ if (!dbus_py_insert_float_types(this_module)) goto init_error;
+ if (!dbus_py_insert_container_types(this_module)) goto init_error;
+ if (!dbus_py_insert_byte_types(this_module)) goto init_error;
+ if (!dbus_py_insert_message_types(this_module)) goto init_error;
+ if (!dbus_py_insert_pending_call(this_module)) goto init_error;
+ if (!dbus_py_insert_mainloop_types(this_module)) goto init_error;
+ if (!dbus_py_insert_libdbus_conn_types(this_module)) goto init_error;
+ if (!dbus_py_insert_conn_types(this_module)) goto init_error;
+ if (!dbus_py_insert_server_types(this_module)) goto init_error;
+
+ if (PyModule_AddStringConstant(this_module, "BUS_DAEMON_NAME",
+ DBUS_SERVICE_DBUS) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "BUS_DAEMON_PATH",
+ DBUS_PATH_DBUS) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "BUS_DAEMON_IFACE",
+ DBUS_INTERFACE_DBUS) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "LOCAL_PATH",
+ DBUS_PATH_LOCAL) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "LOCAL_IFACE",
+ DBUS_INTERFACE_LOCAL) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "INTROSPECTABLE_IFACE",
+ DBUS_INTERFACE_INTROSPECTABLE) < 0)
+ goto init_error;
+ if (PyModule_AddStringConstant(this_module, "PEER_IFACE",
+ DBUS_INTERFACE_PEER) < 0) goto init_error;
+ if (PyModule_AddStringConstant(this_module, "PROPERTIES_IFACE",
+ DBUS_INTERFACE_PROPERTIES) < 0)
+ goto init_error;
+ if (PyModule_AddStringConstant(this_module,
+ "DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER",
+ DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER) < 0)
+ goto init_error;
+ if (PyModule_AddStringConstant(this_module,
+ "DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER",
+ DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER) < 0)
+ goto init_error;
+ if (PyModule_AddStringConstant(this_module,
+ "DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE",
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE) < 0)
+ goto init_error;
+
+#define ADD_CONST_VAL(x, v) \
+ if (PyModule_AddIntConstant(this_module, x, v) < 0) goto init_error;
+#define ADD_CONST_PREFIXED(x) ADD_CONST_VAL(#x, DBUS_##x)
+#define ADD_CONST(x) ADD_CONST_VAL(#x, x)
+
+ ADD_CONST(DBUS_START_REPLY_SUCCESS)
+ ADD_CONST(DBUS_START_REPLY_ALREADY_RUNNING)
+
+ ADD_CONST_PREFIXED(RELEASE_NAME_REPLY_RELEASED)
+ ADD_CONST_PREFIXED(RELEASE_NAME_REPLY_NON_EXISTENT)
+ ADD_CONST_PREFIXED(RELEASE_NAME_REPLY_NOT_OWNER)
+
+ ADD_CONST_PREFIXED(REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ ADD_CONST_PREFIXED(REQUEST_NAME_REPLY_IN_QUEUE)
+ ADD_CONST_PREFIXED(REQUEST_NAME_REPLY_EXISTS)
+ ADD_CONST_PREFIXED(REQUEST_NAME_REPLY_ALREADY_OWNER)
+
+ ADD_CONST_PREFIXED(NAME_FLAG_ALLOW_REPLACEMENT)
+ ADD_CONST_PREFIXED(NAME_FLAG_REPLACE_EXISTING)
+ ADD_CONST_PREFIXED(NAME_FLAG_DO_NOT_QUEUE)
+
+ ADD_CONST_PREFIXED(BUS_SESSION)
+ ADD_CONST_PREFIXED(BUS_SYSTEM)
+ ADD_CONST_PREFIXED(BUS_STARTER)
+
+ ADD_CONST_PREFIXED(MESSAGE_TYPE_INVALID)
+ ADD_CONST_PREFIXED(MESSAGE_TYPE_METHOD_CALL)
+ ADD_CONST_PREFIXED(MESSAGE_TYPE_METHOD_RETURN)
+ ADD_CONST_PREFIXED(MESSAGE_TYPE_ERROR)
+ ADD_CONST_PREFIXED(MESSAGE_TYPE_SIGNAL)
+
+ ADD_CONST_PREFIXED(TYPE_INVALID)
+ ADD_CONST_PREFIXED(TYPE_BYTE)
+ ADD_CONST_PREFIXED(TYPE_BOOLEAN)
+ ADD_CONST_PREFIXED(TYPE_INT16)
+ ADD_CONST_PREFIXED(TYPE_UINT16)
+ ADD_CONST_PREFIXED(TYPE_INT32)
+#ifdef DBUS_TYPE_UNIX_FD
+ ADD_CONST_PREFIXED(TYPE_UNIX_FD)
+#endif
+ ADD_CONST_PREFIXED(TYPE_UINT32)
+ ADD_CONST_PREFIXED(TYPE_INT64)
+ ADD_CONST_PREFIXED(TYPE_UINT64)
+ ADD_CONST_PREFIXED(TYPE_DOUBLE)
+ ADD_CONST_PREFIXED(TYPE_STRING)
+ ADD_CONST_PREFIXED(TYPE_OBJECT_PATH)
+ ADD_CONST_PREFIXED(TYPE_SIGNATURE)
+ ADD_CONST_PREFIXED(TYPE_ARRAY)
+ ADD_CONST_PREFIXED(TYPE_STRUCT)
+ ADD_CONST_VAL("STRUCT_BEGIN", DBUS_STRUCT_BEGIN_CHAR)
+ ADD_CONST_VAL("STRUCT_END", DBUS_STRUCT_END_CHAR)
+ ADD_CONST_PREFIXED(TYPE_VARIANT)
+ ADD_CONST_PREFIXED(TYPE_DICT_ENTRY)
+ ADD_CONST_VAL("DICT_ENTRY_BEGIN", DBUS_DICT_ENTRY_BEGIN_CHAR)
+ ADD_CONST_VAL("DICT_ENTRY_END", DBUS_DICT_ENTRY_END_CHAR)
+
+ ADD_CONST_PREFIXED(HANDLER_RESULT_HANDLED)
+ ADD_CONST_PREFIXED(HANDLER_RESULT_NOT_YET_HANDLED)
+ ADD_CONST_PREFIXED(HANDLER_RESULT_NEED_MEMORY)
+
+ ADD_CONST_PREFIXED(WATCH_READABLE)
+ ADD_CONST_PREFIXED(WATCH_WRITABLE)
+ ADD_CONST_PREFIXED(WATCH_HANGUP)
+ ADD_CONST_PREFIXED(WATCH_ERROR)
+
+ if (PyModule_AddStringConstant(this_module, "__docformat__",
+ "restructuredtext") < 0) goto init_error;
+
+ if (PyModule_AddStringConstant(this_module, "__version__",
+ PACKAGE_VERSION) < 0) goto init_error;
+
+ if (PyModule_AddIntConstant(this_module, "_python_version",
+ PY_VERSION_HEX) < 0) goto init_error;
+
+#ifdef PY3
+ c_api = PyCapsule_New((void *)dbus_bindings_API,
+ PYDBUS_CAPSULE_NAME, NULL);
+#else
+ c_api = PyCObject_FromVoidPtr ((void *)dbus_bindings_API, NULL);
+#endif
+ if (!c_api) {
+ goto init_error;
+ }
+ PyModule_AddObject(this_module, "_C_API", c_api);
+
+#ifdef PY3
+ return this_module;
+ init_error:
+ Py_CLEAR(this_module);
+ return NULL;
+#else
+ init_error:
+ return;
+#endif
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/pending-call.c b/dbus_bindings/pending-call.c
new file mode 100644
index 0000000..469c997
--- /dev/null
+++ b/dbus_bindings/pending-call.c
@@ -0,0 +1,294 @@
+/* Implementation of PendingCall helper type for D-Bus bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+PyDoc_STRVAR(PendingCall_tp_doc,
+"Object representing a pending D-Bus call, returned by\n"
+"Connection.send_message_with_reply(). Cannot be instantiated directly.\n"
+);
+
+static PyTypeObject PendingCallType;
+
+static inline int PendingCall_Check (PyObject *o)
+{
+ return (Py_TYPE(o) == &PendingCallType)
+ || PyObject_IsInstance(o, (PyObject *)&PendingCallType);
+}
+
+typedef struct {
+ PyObject_HEAD
+ DBusPendingCall *pc;
+} PendingCall;
+
+PyDoc_STRVAR(PendingCall_cancel__doc__,
+"cancel()\n\n"
+"Cancel this pending call. Its reply will be ignored and the associated\n"
+"reply handler will never be called.\n");
+static PyObject *
+PendingCall_cancel(PendingCall *self, PyObject *unused UNUSED)
+{
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_cancel(self->pc);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(PendingCall_block__doc__,
+"block()\n\n"
+"Block until this pending call has completed and the associated\n"
+"reply handler has been called.\n"
+"\n"
+"This can lead to a deadlock, if the called method tries to make a\n"
+"synchronous call to a method in this application.\n");
+static PyObject *
+PendingCall_block(PendingCall *self, PyObject *unused UNUSED)
+{
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_block(self->pc);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+static void
+_pending_call_notify_function(DBusPendingCall *pc,
+ PyObject *list)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ /* BEGIN CRITICAL SECTION
+ * While holding the GIL, make sure the callback only gets called once
+ * by deleting it from the 1-item list that's held by libdbus.
+ */
+ PyObject *handler = PyList_GetItem(list, 0);
+ DBusMessage *msg;
+
+ if (!handler) {
+ PyErr_Print();
+ goto release;
+ }
+ if (handler == Py_None) {
+ /* We've already called (and thrown away) the callback */
+ goto release;
+ }
+ Py_INCREF(handler); /* previously borrowed from the list, now owned */
+ Py_INCREF(Py_None); /* take a ref so SetItem can steal it */
+ PyList_SetItem(list, 0, Py_None);
+ /* END CRITICAL SECTION */
+
+ msg = dbus_pending_call_steal_reply(pc);
+
+ if (!msg) {
+ /* omg, what happened here? the notify should only get called
+ * when we have a reply */
+ PyErr_Warn(PyExc_UserWarning, "D-Bus notify function was called "
+ "for an incomplete pending call (shouldn't happen)");
+ } else {
+ PyObject *msg_obj = DBusPyMessage_ConsumeDBusMessage(msg);
+
+ if (msg_obj) {
+ PyObject *ret = PyObject_CallFunctionObjArgs(handler, msg_obj, NULL);
+
+ if (!ret) {
+ PyErr_Print();
+ }
+ Py_CLEAR(ret);
+ Py_CLEAR(msg_obj);
+ }
+ /* else OOM has happened - not a lot we can do about that,
+ * except possibly making it fatal (FIXME?) */
+ }
+
+release:
+ Py_CLEAR(handler);
+ PyGILState_Release(gil);
+}
+
+PyDoc_STRVAR(PendingCall_get_completed__doc__,
+"get_completed() -> bool\n\n"
+"Return true if this pending call has completed.\n\n"
+"If so, its associated reply handler has been called and it is no\n"
+"longer meaningful to cancel it.\n");
+static PyObject *
+PendingCall_get_completed(PendingCall *self, PyObject *unused UNUSED)
+{
+ dbus_bool_t ret;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_pending_call_get_completed(self->pc);
+ Py_END_ALLOW_THREADS
+ return PyBool_FromLong(ret);
+}
+
+/* Steals the reference to the pending call. */
+PyObject *
+DBusPyPendingCall_ConsumeDBusPendingCall(DBusPendingCall *pc,
+ PyObject *callable)
+{
+ dbus_bool_t ret;
+ PyObject *list = PyList_New(1);
+ PendingCall *self = PyObject_New(PendingCall, &PendingCallType);
+
+ if (!list || !self) {
+ Py_CLEAR(list);
+ Py_CLEAR(self);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_cancel(pc);
+ dbus_pending_call_unref(pc);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+
+ /* INCREF because SET_ITEM steals a ref */
+ Py_INCREF(callable);
+ PyList_SET_ITEM(list, 0, callable);
+
+ /* INCREF so we can give a ref to set_notify and still have one */
+ Py_INCREF(list);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_pending_call_set_notify(pc,
+ (DBusPendingCallNotifyFunction)_pending_call_notify_function,
+ (void *)list, (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
+ Py_END_ALLOW_THREADS
+
+ if (!ret) {
+ PyErr_NoMemory();
+ /* DECREF twice - one for the INCREF and one for the allocation */
+ Py_DECREF(list);
+ Py_CLEAR(list);
+ Py_CLEAR(self);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_cancel(pc);
+ dbus_pending_call_unref(pc);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+
+ /* As Alexander Larsson pointed out on dbus@lists.fd.o on 2006-11-30,
+ * the API has a race condition if set_notify runs in one thread and a
+ * mail loop runs in another - if the reply gets in before set_notify
+ * runs, the notify isn't called and there is no indication of error.
+ *
+ * The workaround is to check for completion immediately, but this also
+ * has a race which might lead to getting the notify called twice if
+ * we're unlucky. So I use the list to arrange for the notify to be
+ * deleted before it's called for the second time. The GIL protects
+ * the critical section in which I delete the callback from the list.
+ */
+ if (dbus_pending_call_get_completed(pc)) {
+ /* the first race condition happened, so call the callable here.
+ * FIXME: we ought to arrange for the callable to run from the
+ * mainloop thread, like it would if the race hadn't happened...
+ * this needs a better mainloop abstraction, though.
+ */
+ _pending_call_notify_function(pc, list);
+ }
+
+ Py_CLEAR(list);
+ self->pc = pc;
+ return (PyObject *)self;
+}
+
+static void
+PendingCall_tp_dealloc (PendingCall *self)
+{
+ if (self->pc) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_unref(self->pc);
+ Py_END_ALLOW_THREADS
+ }
+ PyObject_Del (self);
+}
+
+static PyMethodDef PendingCall_tp_methods[] = {
+ {"block", (PyCFunction)PendingCall_block, METH_NOARGS,
+ PendingCall_block__doc__},
+ {"cancel", (PyCFunction)PendingCall_cancel, METH_NOARGS,
+ PendingCall_cancel__doc__},
+ {"get_completed", (PyCFunction)PendingCall_get_completed, METH_NOARGS,
+ PendingCall_get_completed__doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject PendingCallType = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.lowlevel.PendingCall",
+ sizeof(PendingCall),
+ 0,
+ (destructor)PendingCall_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ PendingCall_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ PendingCall_tp_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ /* deliberately not callable! Use PendingCall_ConsumeDBusPendingCall */
+ 0, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_pending_call (void)
+{
+ if (PyType_Ready (&PendingCallType) < 0) return 0;
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_pending_call (PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&PendingCallType);
+ if (PyModule_AddObject (this_module, "PendingCall",
+ (PyObject *)&PendingCallType) < 0) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/server.c b/dbus_bindings/server.c
new file mode 100644
index 0000000..3ce67c2
--- /dev/null
+++ b/dbus_bindings/server.c
@@ -0,0 +1,618 @@
+/* Implementation of the _dbus_bindings Server type, a Python wrapper
+ * for DBusServer.
+ *
+ * Copyright (C) 2008 Openismus GmbH <http://openismus.com/>
+ * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+/* Server definition ================================================ */
+
+typedef struct {
+ PyObject_HEAD
+ DBusServer *server;
+
+ /* The Connection subtype for which this Server is a factory */
+ PyObject *conn_class;
+
+ /* Weak-references list to make server weakly referenceable */
+ PyObject *weaklist;
+
+ PyObject *mainloop;
+} Server;
+
+PyDoc_STRVAR(Server_tp_doc,
+"A D-Bus server.\n"
+"\n"
+"::\n"
+"\n"
+" Server(address, connection_subtype, mainloop=None, auth_mechanisms=None)\n"
+" -> Server\n"
+);
+
+/* D-Bus Server user data slot, containing an owned reference to either
+ * the Server, or a weakref to the Server.
+ */
+static dbus_int32_t _server_python_slot;
+
+/* C API for main-loop hooks ======================================== */
+
+/* Return a borrowed reference to the DBusServer which underlies this
+ * Server. */
+DBusServer *
+DBusPyServer_BorrowDBusServer(PyObject *self)
+{
+ DBusServer *dbs;
+
+ TRACE(self);
+ if (!DBusPyServer_Check(self)) {
+ PyErr_SetString(PyExc_TypeError, "A dbus.server.Server is required");
+ return NULL;
+ }
+ dbs = ((Server *)self)->server;
+ if (!dbs) {
+ PyErr_SetString(PyExc_RuntimeError, "Server is in an invalid "
+ "state: no DBusServer");
+ return NULL;
+ }
+ return dbs;
+}
+
+/* Internal C API =================================================== */
+
+static dbus_bool_t
+DBusPyServer_set_auth_mechanisms(Server *self,
+ PyObject *auth_mechanisms)
+{
+ PyObject *fast_seq = NULL, *references = NULL;
+ Py_ssize_t length;
+ Py_ssize_t i;
+ /* a mutable array of constant strings */
+ const char **list = NULL;
+ dbus_bool_t ret = FALSE;
+
+ fast_seq = PySequence_Fast(auth_mechanisms,
+ "Expecting sequence for auth_mechanisms parameter");
+
+ if (!fast_seq)
+ return FALSE;
+
+ length = PySequence_Fast_GET_SIZE(fast_seq);
+
+ list = calloc (length + 1, sizeof (char *));
+
+ if (!list) {
+ PyErr_NoMemory();
+ goto finally;
+ }
+
+ if (!(references = PyTuple_New(length)))
+ goto finally;
+
+ for (i = 0; i < length; ++i) {
+ PyObject *am, *am_as_bytes;
+
+ am = PySequence_Fast_GET_ITEM(auth_mechanisms, i);
+ if (!am)
+ goto finally;
+
+ if (PyUnicode_Check(am)) {
+ am_as_bytes = PyUnicode_AsUTF8String(am);
+ if (!am_as_bytes)
+ goto finally;
+ }
+ else {
+ am_as_bytes = am;
+ Py_INCREF(am_as_bytes);
+ }
+ list[i] = PyBytes_AsString(am_as_bytes);
+ if (!list[i])
+ goto finally;
+
+ PyTuple_SET_ITEM(references, i, am_as_bytes);
+ }
+
+ list[length] = NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ dbus_server_set_auth_mechanisms(self->server, list);
+ Py_END_ALLOW_THREADS
+
+ ret = TRUE;
+
+finally:
+ if (list)
+ free (list);
+ Py_CLEAR(fast_seq);
+ Py_CLEAR(references);
+ return ret;
+}
+
+/* Return a new reference to a Python Server or subclass corresponding
+ * to the DBusServer server. For use in callbacks.
+ *
+ * Raises AssertionError if the DBusServer does not have a Server.
+ */
+static PyObject *
+DBusPyServer_ExistingFromDBusServer(DBusServer *server)
+{
+ PyObject *self, *ref;
+
+ Py_BEGIN_ALLOW_THREADS
+ ref = (PyObject *)dbus_server_get_data(server,
+ _server_python_slot);
+ Py_END_ALLOW_THREADS
+ if (ref) {
+ DBG("(DBusServer *)%p has weak reference at %p", server, ref);
+ self = PyWeakref_GetObject(ref); /* still a borrowed ref */
+ if (self && self != Py_None && DBusPyServer_Check(self)) {
+ DBG("(DBusServer *)%p has weak reference at %p pointing to %p",
+ server, ref, self);
+ TRACE(self);
+ Py_INCREF(self);
+ TRACE(self);
+ return self;
+ }
+ }
+
+ PyErr_SetString(PyExc_AssertionError,
+ "D-Bus server does not have a Server "
+ "instance associated with it");
+ return NULL;
+}
+
+static void
+DBusPyServer_new_connection_cb(DBusServer *server,
+ DBusConnection *conn,
+ void *data UNUSED)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ PyObject *self = NULL;
+ PyObject *method = NULL;
+
+ self = DBusPyServer_ExistingFromDBusServer(server);
+ if (!self) goto out;
+ TRACE(self);
+
+ method = PyObject_GetAttrString(self, "_on_new_connection");
+ TRACE(method);
+
+ if (method) {
+ PyObject *conn_class = ((Server *)self)->conn_class;
+ PyObject *wrapper = DBusPyLibDBusConnection_New(conn);
+ PyObject *conn_obj;
+ PyObject *result;
+
+ if (!wrapper)
+ goto out;
+
+ conn_obj = PyObject_CallFunctionObjArgs((PyObject *)conn_class,
+ wrapper, ((Server*) self)->mainloop, NULL);
+ Py_CLEAR(wrapper);
+
+ if (!conn_obj)
+ goto out;
+
+ result = PyObject_CallFunctionObjArgs(method, conn_obj, NULL);
+ Py_CLEAR (conn_obj);
+
+ /* discard result if not NULL, and fall through regardless */
+ Py_CLEAR(result);
+ }
+
+out:
+ Py_CLEAR(method);
+ Py_CLEAR(self);
+
+ if (PyErr_Occurred())
+ PyErr_Print();
+
+ PyGILState_Release(gil);
+}
+
+/* Return a new reference to a Python Server or subclass (given by cls)
+ * corresponding to the DBusServer server, which must have been newly
+ * created. For use by the Server constructor.
+ *
+ * Raises AssertionError if the DBusServer already has a Server.
+ *
+ * One reference to server is stolen - either the returned DBusPyServer
+ * claims it, or it's unreffed.
+ */
+static PyObject *
+DBusPyServer_NewConsumingDBusServer(PyTypeObject *cls,
+ DBusServer *server,
+ PyObject *conn_class,
+ PyObject *mainloop,
+ PyObject *auth_mechanisms)
+{
+ Server *self = NULL;
+ PyObject *ref;
+ dbus_bool_t ok;
+
+ DBG("%s(cls=%p, server=%p, mainloop=%p, auth_mechanisms=%p)",
+ __func__, cls, server, mainloop, auth_mechanisms);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(server);
+
+ Py_BEGIN_ALLOW_THREADS
+ ref = (PyObject *)dbus_server_get_data(server,
+ _server_python_slot);
+ Py_END_ALLOW_THREADS
+ if (ref) {
+ self = (Server *)PyWeakref_GetObject(ref);
+ ref = NULL;
+ if (self && (PyObject *)self != Py_None) {
+ self = NULL;
+ PyErr_SetString(PyExc_AssertionError,
+ "Newly created D-Bus server already has a "
+ "Server instance associated with it");
+ DBG("%s() fail - assertion failed, DBusPyServer has a DBusServer already", __func__);
+ DBG_WHEREAMI;
+ return NULL;
+ }
+ }
+ ref = NULL;
+
+ /* Change mainloop from a borrowed reference to an owned reference */
+ if (!mainloop || mainloop == Py_None) {
+ mainloop = dbus_py_get_default_main_loop();
+
+ if (!mainloop || mainloop == Py_None) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "To run a D-Bus server, you need to either "
+ "pass mainloop=... to the constructor or call "
+ "dbus.set_default_main_loop(...)");
+ goto err;
+ }
+ }
+ else {
+ Py_INCREF(mainloop);
+ }
+
+ DBG("Constructing Server from DBusServer at %p", server);
+
+ self = (Server *)(cls->tp_alloc(cls, 0));
+ if (!self) goto err;
+ TRACE(self);
+
+ DBG_WHEREAMI;
+
+ self->server = NULL;
+
+ Py_INCREF(conn_class);
+ self->conn_class = conn_class;
+
+ self->mainloop = mainloop;
+ mainloop = NULL; /* don't DECREF it - the DBusServer owns it now */
+
+ ref = PyWeakref_NewRef((PyObject *)self, NULL);
+ if (!ref) goto err;
+ DBG("Created weak ref %p to (Server *)%p for (DBusServer *)%p",
+ ref, self, server);
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_server_set_data(server, _server_python_slot,
+ (void *)ref,
+ (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
+ Py_END_ALLOW_THREADS
+
+ if (ok) {
+ DBG("Attached weak ref %p ((Server *)%p) to (DBusServer *)%p",
+ ref, self, server);
+
+ ref = NULL; /* don't DECREF it - the DBusServer owns it now */
+ }
+ else {
+ DBG("Failed to attached weak ref %p ((Server *)%p) to "
+ "(DBusServer *)%p - will dispose of it", ref, self, server);
+ PyErr_NoMemory();
+ goto err;
+ }
+
+ DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(server, err);
+ self->server = server;
+ /* the DBusPyServer will close it now */
+ server = NULL;
+
+ if (self->mainloop != Py_None &&
+ !dbus_py_set_up_server((PyObject *)self, self->mainloop))
+ goto err;
+
+ if (auth_mechanisms && auth_mechanisms != Py_None &&
+ !DBusPyServer_set_auth_mechanisms(self, auth_mechanisms))
+ goto err;
+
+ Py_BEGIN_ALLOW_THREADS
+ dbus_server_set_new_connection_function(self->server,
+ DBusPyServer_new_connection_cb,
+ NULL, NULL);
+ Py_END_ALLOW_THREADS
+
+ DBG("%s() -> %p", __func__, self);
+ TRACE(self);
+ return (PyObject *)self;
+
+err:
+ DBG("Failed to construct Server from DBusServer at %p", server);
+ Py_CLEAR(mainloop);
+ Py_CLEAR(self);
+ Py_CLEAR(ref);
+
+ if (server) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_server_disconnect(server);
+ dbus_server_unref(server);
+ Py_END_ALLOW_THREADS
+ }
+
+ DBG("%s() fail", __func__);
+ DBG_WHEREAMI;
+ return NULL;
+}
+
+/* Server type-methods ============================================== */
+
+static PyObject *
+Server_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ DBusServer *server;
+ const char *address;
+ DBusError error;
+ PyObject *self, *conn_class, *mainloop = NULL, *auth_mechanisms = NULL;
+ static char *argnames[] = { "address", "connection_class", "mainloop",
+ "auth_mechanisms", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|OO", argnames,
+ &address, &conn_class, &mainloop, &auth_mechanisms)) {
+ return NULL;
+ }
+
+ if (!PyType_Check(conn_class) ||
+ !PyType_IsSubtype((PyTypeObject *) conn_class, &DBusPyConnection_Type)) {
+ /* strictly speaking, it can be any subtype of
+ * _dbus_bindings._Connection - but nobody else should be subtyping
+ * that, so let's keep this slightly inaccurate message */
+ PyErr_SetString(PyExc_TypeError, "connection_class must be "
+ "dbus.connection.Connection or a subtype");
+ return NULL;
+ }
+
+ dbus_error_init(&error);
+
+ Py_BEGIN_ALLOW_THREADS
+ server = dbus_server_listen(address, &error);
+ Py_END_ALLOW_THREADS
+
+ if (!server) {
+ DBusPyException_ConsumeError(&error);
+ return NULL;
+ }
+
+ self = DBusPyServer_NewConsumingDBusServer(cls, server, conn_class,
+ mainloop, auth_mechanisms);
+
+ if (!self) {
+ return NULL;
+ }
+
+ ((Server *)self)->weaklist = NULL;
+ TRACE(self);
+
+ return self;
+}
+
+/* Destructor */
+static void Server_tp_dealloc(Server *self)
+{
+ DBusServer *server = self->server;
+ PyObject *et, *ev, *etb;
+
+ /* avoid clobbering any pending exception */
+ PyErr_Fetch(&et, &ev, &etb);
+
+ if (self->weaklist) {
+ PyObject_ClearWeakRefs((PyObject *)self);
+ }
+
+ TRACE(self);
+ DBG("Deallocating Server at %p (DBusServer at %p)", self, server);
+ DBG_WHEREAMI;
+
+ if (server) {
+ DBG("Server at %p has a server, disconnecting it...", self);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_server_disconnect(server);
+ Py_END_ALLOW_THREADS
+ }
+
+ Py_CLEAR(self->mainloop);
+
+ /* make sure to do this last to preserve the invariant that
+ * self->server is always non-NULL for any referenced Server.
+ */
+ DBG("Server at %p: nulling self->server", self);
+ self->server = NULL;
+
+ if (server) {
+ DBG("Server at %p: unreffing server", self);
+ dbus_server_unref(server);
+ }
+
+ DBG("Server at %p: freeing self", self);
+ PyErr_Restore(et, ev, etb);
+ (Py_TYPE(self)->tp_free)((PyObject *)self);
+}
+
+PyDoc_STRVAR(Server_disconnect__doc__,
+"disconnect()\n\n"
+"Releases the server's address and stops listening for new clients.\n\n"
+"If called more than once, only the first call has an effect.");
+static PyObject *
+Server_disconnect (Server *self, PyObject *args UNUSED)
+{
+ TRACE(self);
+ if (self->server) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_server_disconnect(self->server);
+ Py_END_ALLOW_THREADS
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Server_get_address__doc__,
+"get_address() -> str\n\n"
+"Returns the address of the server.");
+static PyObject *
+Server_get_address(Server *self, PyObject *args UNUSED)
+{
+ const char *address;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->server);
+ Py_BEGIN_ALLOW_THREADS
+ address = dbus_server_get_address(self->server);
+ Py_END_ALLOW_THREADS
+
+ return NATIVESTR_FROMSTR(address);
+}
+
+PyDoc_STRVAR(Server_get_id__doc__,
+"get_id() -> str\n\n"
+"Returns the unique ID of the server.");
+static PyObject *
+Server_get_id(Server *self, PyObject *args UNUSED)
+{
+ const char *id;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->server);
+ Py_BEGIN_ALLOW_THREADS
+ id = dbus_server_get_id(self->server);
+ Py_END_ALLOW_THREADS
+
+ return NATIVESTR_FROMSTR(id);
+}
+
+PyDoc_STRVAR(Server_get_is_connected__doc__,
+"get_is_connected() -> bool\n\n"
+"Return true if this Server is still listening for new connections.\n");
+static PyObject *
+Server_get_is_connected (Server *self, PyObject *args UNUSED)
+{
+ dbus_bool_t ret;
+
+ TRACE(self);
+ DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->server);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_server_get_is_connected(self->server);
+ Py_END_ALLOW_THREADS
+ return PyBool_FromLong(ret);
+}
+
+/* Server type object =============================================== */
+
+struct PyMethodDef DBusPyServer_tp_methods[] = {
+#define ENTRY(name, flags) {#name, (PyCFunction)Server_##name, flags, Server_##name##__doc__}
+ ENTRY(disconnect, METH_NOARGS),
+ ENTRY(get_address, METH_NOARGS),
+ ENTRY(get_id, METH_NOARGS),
+ ENTRY(get_is_connected, METH_NOARGS),
+ {NULL},
+#undef ENTRY
+};
+
+PyTypeObject DBusPyServer_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_dbus_bindings._Server",/*tp_name*/
+ sizeof(Server), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)Server_tp_dealloc,
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+#ifdef PY3
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE,
+#endif
+ Server_tp_doc, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ offsetof(Server, weaklist), /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ DBusPyServer_tp_methods,/*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ 0, /*tp_init*/
+ 0, /*tp_alloc*/
+ Server_tp_new, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+};
+
+dbus_bool_t
+dbus_py_init_server_types(void)
+{
+ /* Get a slot to store our weakref on DBus Server */
+ _server_python_slot = -1;
+ if (!dbus_server_allocate_data_slot(&_server_python_slot))
+ return FALSE;
+
+ if (PyType_Ready(&DBusPyServer_Type) < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+dbus_bool_t
+dbus_py_insert_server_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF (&DBusPyServer_Type);
+ if (PyModule_AddObject(this_module, "_Server",
+ (PyObject *)&DBusPyServer_Type) < 0) return FALSE;
+
+ return TRUE;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/signature.c b/dbus_bindings/signature.c
new file mode 100644
index 0000000..e3a555c
--- /dev/null
+++ b/dbus_bindings/signature.c
@@ -0,0 +1,257 @@
+/* Implementation of Signature type for D-Bus bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+PyDoc_STRVAR(Signature_tp_doc,
+"A string subclass whose values are restricted to valid D-Bus\n"
+"signatures. When iterated over, instead of individual characters it\n"
+"produces Signature instances representing single complete types.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" ``Signature(value: str or unicode[, variant_level: int]) -> Signature``\n"
+"\n"
+"``value`` must be a valid D-Bus signature (zero or more single complete\n"
+"types).\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a signature, this is represented in Python by a\n"
+" Signature with variant_level==2.\n"
+);
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *bytes;
+ DBusSignatureIter iter;
+} SignatureIter;
+
+static void
+SignatureIter_tp_dealloc (SignatureIter *self)
+{
+ Py_CLEAR(self->bytes);
+ PyObject_Del(self);
+}
+
+static PyObject *
+SignatureIter_tp_iternext (SignatureIter *self)
+{
+ char *sig;
+ PyObject *obj;
+
+ /* Stop immediately if finished or not correctly initialized */
+ if (!self->bytes) return NULL;
+
+ sig = dbus_signature_iter_get_signature(&(self->iter));
+ if (!sig) return PyErr_NoMemory();
+ obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "s", sig);
+ dbus_free(sig);
+ if (!obj) return NULL;
+
+ if (!dbus_signature_iter_next(&(self->iter))) {
+ /* mark object as having been finished with */
+ Py_CLEAR(self->bytes);
+ }
+
+ return obj;
+}
+
+static PyObject *
+SignatureIter_tp_iter(PyObject *self)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyTypeObject SignatureIterType = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "_dbus_bindings._SignatureIter",
+ sizeof(SignatureIter),
+ 0,
+ (destructor)SignatureIter_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ SignatureIter_tp_iter, /* tp_iter */
+ (iternextfunc)SignatureIter_tp_iternext, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ /* deliberately not callable! Use iter(Signature) instead */
+ 0, /* tp_new */
+ 0, /* tp_free */
+};
+
+static PyObject *
+Signature_tp_iter(PyObject *self)
+{
+ SignatureIter *iter = PyObject_New(SignatureIter, &SignatureIterType);
+ PyObject *self_as_bytes;
+
+ if (!iter) return NULL;
+
+#ifdef PY3
+ self_as_bytes = PyUnicode_AsUTF8String(self);
+ if (!self_as_bytes) {
+ Py_CLEAR(iter);
+ return NULL;
+ }
+#else
+ self_as_bytes = self;
+ Py_INCREF(self_as_bytes);
+#endif
+
+ if (PyBytes_GET_SIZE(self_as_bytes) > 0) {
+ iter->bytes = self_as_bytes;
+ dbus_signature_iter_init(&(iter->iter),
+ PyBytes_AS_STRING(self_as_bytes));
+ }
+ else {
+ /* this is a null string, make a null iterator */
+ iter->bytes = NULL;
+ Py_CLEAR(self_as_bytes);
+ }
+ return (PyObject *)iter;
+}
+
+static PyObject *
+Signature_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ const char *str = NULL;
+ PyObject *ignored;
+ static char *argnames[] = {"object_path", "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|O:__new__", argnames,
+ &str, &ignored)) return NULL;
+ if (!dbus_signature_validate(str, NULL)) {
+ PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
+ return NULL;
+ }
+ return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs);
+}
+
+PyTypeObject DBusPySignature_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Signature",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Signature_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ Signature_tp_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Signature_tp_new, /* tp_new */
+ 0, /* tp_free */
+};
+
+dbus_bool_t
+dbus_py_init_signature(void)
+{
+ if (PyType_Ready(&SignatureIterType) < 0) return 0;
+
+ DBusPySignature_Type.tp_base = &DBusPyStrBase_Type;
+ if (PyType_Ready(&DBusPySignature_Type) < 0) return 0;
+ DBusPySignature_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_signature(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPySignature_Type);
+ if (PyModule_AddObject(this_module, "Signature",
+ (PyObject *)&DBusPySignature_Type) < 0) return 0;
+ Py_INCREF(&SignatureIterType);
+ if (PyModule_AddObject(this_module, "_SignatureIter",
+ (PyObject *)&SignatureIterType) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/string.c b/dbus_bindings/string.c
new file mode 100644
index 0000000..8363f98
--- /dev/null
+++ b/dbus_bindings/string.c
@@ -0,0 +1,383 @@
+/* Simple D-Bus types: ObjectPath and other string types.
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "types-internal.h"
+#include <structmember.h>
+
+#ifndef PY3
+/* UTF-8 string representation ====================================== */
+
+PyDoc_STRVAR(UTF8String_tp_doc,
+"A string represented using UTF-8 - a subtype of `str`.\n"
+"\n"
+"All strings on D-Bus are required to be valid Unicode; in the \"wire\n"
+"protocol\" they're transported as UTF-8.\n"
+"\n"
+"By default, when byte arrays are converted from D-Bus to Python, they\n"
+"come out as a `dbus.String`, which is a subtype of `unicode`.\n"
+"If you prefer to get UTF-8 strings (as instances of this class) or you\n"
+"want to avoid the conversion overhead of going from UTF-8 to Python's\n"
+"internal Unicode representation, you can pass the ``utf8_strings=True``\n"
+"keyword argument to any of these methods:\n"
+"\n"
+"* any D-Bus method proxy, or ``connect_to_signal``, on the objects returned\n"
+" by `Bus.get_object`\n"
+"* any D-Bus method on a `dbus.Interface`\n"
+"* `dbus.Interface.connect_to_signal`\n"
+"* `Bus.add_signal_receiver`\n"
+"\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.UTF8String(value: str or unicode[, variant_level: int]) -> UTF8String\n"
+"\n"
+"If value is a str object it must be valid UTF-8.\n"
+"\n"
+"variant_level must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a string, this is represented in Python by a\n"
+" String or UTF8String with variant_level==2.\n"
+":Since: 0.80 (in older versions, use dbus.String)\n"
+);
+
+static PyObject *
+UTF8String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ const char *str = NULL;
+ long variantness = 0;
+ static char *argnames[] = {"value", "variant_level", NULL};
+ PyObject *unicode;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|l:__new__", argnames,
+ &str, &variantness)) return NULL;
+ unicode = PyUnicode_DecodeUTF8(str, strlen(str), NULL);
+ if (!unicode) return NULL;
+ Py_CLEAR(unicode);
+ return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs);
+}
+
+PyTypeObject DBusPyUTF8String_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.UTF8String",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UTF8String_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ UTF8String_tp_new, /* tp_new */
+};
+#endif /* !PY3 */
+
+/* Object path ====================================================== */
+
+PyDoc_STRVAR(ObjectPath_tp_doc,
+"A D-Bus object path, such as '/com/example/MyApp/Documents/abc'.\n"
+"\n"
+"ObjectPath is a subtype of str, and object-paths behave like strings.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.ObjectPath(path: str, variant_level: int) -> ObjectPath\n"
+"\n"
+"path must be an ASCII string following the syntax of object paths.\n"
+"variant_level must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an object path, this is represented in Python by an\n"
+" ObjectPath with variant_level==2.\n"
+);
+
+static PyObject *
+ObjectPath_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ const char *str = NULL;
+ long variantness = 0;
+ static char *argnames[] = {"object_path", "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|l:__new__", argnames,
+ &str, &variantness)) return NULL;
+ if (!dbus_py_validate_object_path(str)) {
+ return NULL;
+ }
+ return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs);
+}
+
+PyTypeObject DBusPyObjectPath_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.ObjectPath",
+ 0,
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ObjectPath_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ ObjectPath_tp_new, /* tp_new */
+};
+
+/* Unicode string representation ==================================== */
+
+PyDoc_STRVAR(String_tp_doc,
+"A string represented using Unicode - a subtype of `unicode`.\n"
+"\n"
+"All strings on D-Bus are required to be valid Unicode; in the \"wire\n"
+"protocol\" they're transported as UTF-8.\n"
+"\n"
+"By default, when strings are converted from D-Bus to Python, they\n"
+"come out as this class. If you prefer to get UTF-8 strings (as instances\n"
+"of a subtype of `str`) or you want to avoid the conversion overhead of\n"
+"going from UTF-8 to Python's internal Unicode representation, see the\n"
+"documentation for `dbus.UTF8String`.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" String(value: str or unicode[, variant_level: int]) -> String\n"
+"\n"
+"variant_level must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a string, this is represented in Python by a\n"
+" String or UTF8String with variant_level==2.\n"
+);
+
+static PyMemberDef String_tp_members[] = {
+ {"variant_level", T_LONG, offsetof(DBusPyString, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant"},
+ {NULL},
+};
+
+static PyObject *
+String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ long variantness = 0;
+ static char *argnames[] = {"variant_level", NULL};
+
+ if (PyTuple_Size(args) > 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes at most one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|l:__new__", argnames,
+ &variantness)) return NULL;
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+ self = (PyUnicode_Type.tp_new)(cls, args, NULL);
+ if (self) {
+ ((DBusPyString *)self)->variant_level = variantness;
+ }
+ return self;
+}
+
+static PyObject *
+String_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyUnicode_Type.tp_repr)(self);
+ PyObject *my_repr;
+
+ if (!parent_repr) {
+ return NULL;
+ }
+ if (((DBusPyString *)self)->variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ ((DBusPyString *)self)->variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V)", Py_TYPE(self)->tp_name,
+ REPRV(parent_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_CLEAR(parent_repr);
+ return my_repr;
+}
+
+PyTypeObject DBusPyString_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.String",
+ sizeof(DBusPyString),
+ 0,
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ String_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ String_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ String_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ DEFERRED_ADDRESS(&PyUnicode_Type), /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ String_tp_new, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_string_types(void)
+{
+ /* don't need to do strange contortions for unicode, since it's not a
+ * "variable-size" object (it has a pointer to its data instead)
+ */
+ if (PyUnicode_Type.tp_itemsize != 0) {
+ fprintf(stderr, "dbus-python is not compatible with this version of "
+ "Python (unicode objects are assumed to be fixed-size)");
+ return 0;
+ }
+ DBusPyString_Type.tp_base = &PyUnicode_Type;
+ if (PyType_Ready(&DBusPyString_Type) < 0) return 0;
+ DBusPyString_Type.tp_print = NULL;
+
+#ifndef PY3
+ DBusPyUTF8String_Type.tp_base = &DBusPyStrBase_Type;
+ if (PyType_Ready(&DBusPyUTF8String_Type) < 0) return 0;
+ DBusPyUTF8String_Type.tp_print = NULL;
+#endif
+
+ DBusPyObjectPath_Type.tp_base = &DBusPyStrBase_Type;
+ if (PyType_Ready(&DBusPyObjectPath_Type) < 0) return 0;
+ DBusPyObjectPath_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_string_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyObjectPath_Type);
+ Py_INCREF(&DBusPyString_Type);
+ if (PyModule_AddObject(this_module, "ObjectPath",
+ (PyObject *)&DBusPyObjectPath_Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "String",
+ (PyObject *)&DBusPyString_Type) < 0) return 0;
+
+#ifndef PY3
+ Py_INCREF(&DBusPyUTF8String_Type);
+ if (PyModule_AddObject(this_module, "UTF8String",
+ (PyObject *)&DBusPyUTF8String_Type) < 0) return 0;
+#endif
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/types-internal.h b/dbus_bindings/types-internal.h
new file mode 100644
index 0000000..041c33b
--- /dev/null
+++ b/dbus_bindings/types-internal.h
@@ -0,0 +1,112 @@
+/* D-Bus types: implementation internals
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+
+/* In Python2 >= 2.6 this aliases PyString to PyBytes. There is no PyString
+ * in Python 3, so this allows the C extension to be compilable in both Python
+ * versions.
+ */
+#include <bytesobject.h>
+
+/* In Python 2.x, we need this to define the type of PyLongObject */
+#ifndef PY3
+#include <longintrepr.h>
+#endif
+
+#ifndef DBUS_BINDINGS_TYPES_INTERNAL_H
+#define DBUS_BINDINGS_TYPES_INTERNAL_H
+
+#ifndef PY3
+extern PyTypeObject DBusPyIntBase_Type;
+DEFINE_CHECK(DBusPyIntBase)
+
+typedef struct {
+ PyIntObject base;
+ long variant_level;
+} DBusPyIntBase;
+#endif
+
+extern PyTypeObject DBusPyLongBase_Type;
+DEFINE_CHECK(DBusPyLongBase)
+
+extern PyTypeObject DBusPyFloatBase_Type;
+DEFINE_CHECK(DBusPyFloatBase)
+
+typedef struct {
+ PyFloatObject base;
+ long variant_level;
+} DBusPyFloatBase;
+
+typedef struct {
+ PyUnicodeObject unicode;
+ long variant_level;
+} DBusPyString;
+
+extern PyTypeObject DBusPyStrBase_Type;
+DEFINE_CHECK(DBusPyStrBase)
+
+#ifdef PY3
+extern PyTypeObject DBusPyBytesBase_Type;
+DEFINE_CHECK(DBusPyBytesBase)
+#endif
+
+dbus_int16_t dbus_py_int16_range_check(PyObject *);
+dbus_uint16_t dbus_py_uint16_range_check(PyObject *);
+dbus_int32_t dbus_py_int32_range_check(PyObject *);
+dbus_uint32_t dbus_py_uint32_range_check(PyObject *);
+
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+# define DBUS_PYTHON_64_BIT_WORKS 1
+dbus_int64_t dbus_py_int64_range_check(PyObject *);
+dbus_uint64_t dbus_py_uint64_range_check(PyObject *);
+#else
+# undef DBUS_PYTHON_64_BIT_WORKS
+#endif /* defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG) */
+
+extern PyObject *dbus_py_variant_level_const;
+extern PyObject *dbus_py_signature_const;
+extern PyObject *dbus_py__dbus_object_path__const;
+
+typedef struct {
+ PyListObject super;
+ PyObject *signature;
+ long variant_level;
+} DBusPyArray;
+
+typedef struct {
+ PyDictObject super;
+ PyObject *signature;
+ long variant_level;
+} DBusPyDict;
+
+PyObject *dbus_py_variant_level_getattro(PyObject *obj, PyObject *name);
+dbus_bool_t dbus_py_variant_level_set(PyObject *obj, long variant_level);
+void dbus_py_variant_level_clear(PyObject *obj);
+long dbus_py_variant_level_get(PyObject *obj);
+
+#endif
diff --git a/dbus_bindings/unixfd.c b/dbus_bindings/unixfd.c
new file mode 100644
index 0000000..648dd2c
--- /dev/null
+++ b/dbus_bindings/unixfd.c
@@ -0,0 +1,254 @@
+/* Simple D-Bus types: Unix FD type.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2010 Signove <http://www.signove.com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include "types-internal.h"
+
+PyDoc_STRVAR(UnixFd_tp_doc,
+"An Unix Fd.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.UnixFd(value: int or file object[, variant_level: int]) -> UnixFd\n"
+"\n"
+"``value`` must be the integer value of a file descriptor, or an object that\n"
+"implements the fileno() method. Otherwise, `ValueError` will be\n"
+"raised.\n"
+"\n"
+"UnixFd keeps a dup() (duplicate) of the supplied file descriptor. The\n"
+"caller remains responsible for closing the original fd.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an Unix Fd, this is represented in Python by an\n"
+" Unix Fd with variant_level==2.\n"
+);
+
+typedef struct {
+ PyObject_HEAD
+ int fd;
+} UnixFdObject;
+
+/* Return values:
+ * -2 - the long value overflows an int
+ * -1 - Python failed producing a long (or in Python 2 an int)
+ * 0 - success
+ * 1 - arg is not a long (or in Python 2 an int)
+ *
+ * Or to summarize:
+ * status < 0 - an error occurred, and a Python exception is set.
+ * status == 0 - all is okay, output argument *fd is set.
+ * status > 0 - try something else
+ */
+static int
+make_fd(PyObject *arg, int *fd)
+{
+ long fd_arg;
+
+ if (INTORLONG_CHECK(arg))
+ {
+ /* on Python 2 this accepts either int or long */
+ fd_arg = PyLong_AsLong(arg);
+ if (fd_arg == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ }
+ else {
+ return 1;
+ }
+ /* Check for int overflow. */
+ if (fd_arg < INT_MIN || fd_arg > INT_MAX) {
+ PyErr_Format(PyExc_ValueError, "int is outside fd range");
+ return -2;
+ }
+ *fd = (int)fd_arg;
+ return 0;
+}
+
+static PyObject *
+UnixFd_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs UNUSED)
+{
+ UnixFdObject *self = NULL;
+ PyObject *arg;
+ int status, fd, fd_original = -1;
+
+ if (!PyArg_ParseTuple(args, "O", &arg, NULL)) {
+ return NULL;
+ }
+
+ status = make_fd(arg, &fd_original);
+ if (status < 0)
+ return NULL;
+
+ if (status > 0) {
+ if (PyObject_HasAttrString(arg, "fileno")) {
+ PyObject *fd_number = PyObject_CallMethod(arg, "fileno", NULL);
+ if (!fd_number)
+ return NULL;
+ status = make_fd(fd_number, &fd_original);
+ Py_CLEAR(fd_number);
+ if (status < 0)
+ return NULL;
+ if (status > 0) {
+ PyErr_Format(PyExc_ValueError, "Argument's fileno() method "
+ "returned a non-int value");
+ return NULL;
+ }
+ /* fd_original is all good. */
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "Argument is not int and does not "
+ "implement fileno() method");
+ return NULL;
+ }
+ }
+ assert(fd_original >= 0);
+ fd = dup(fd_original);
+ if (fd < 0) {
+ PyErr_Format(PyExc_ValueError, "Invalid file descriptor");
+ return NULL;
+ }
+
+ self = (UnixFdObject *) cls->tp_alloc(cls, 0);
+ if (!self)
+ return NULL;
+
+ self->fd = fd;
+ return (PyObject *)self;
+}
+
+static void
+UnixFd_dealloc(UnixFdObject *self)
+{
+ if (self->fd >= 0) {
+ close(self->fd);
+ self->fd = -1;
+ }
+}
+
+PyDoc_STRVAR(UnixFd_take__doc__,
+"take() -> int\n"
+"\n"
+"This method returns the file descriptor owned by UnixFd object.\n"
+"Note that, once this method is called, closing the file descriptor is\n"
+"the caller's responsibility.\n"
+"\n"
+"This method may be called at most once; UnixFd 'forgets' the file\n"
+"descriptor after it is taken.\n"
+"\n"
+":Raises ValueError: if this method has already been called\n"
+);
+static PyObject *
+UnixFd_take(UnixFdObject *self)
+{
+ PyObject *fdnumber;
+
+ if (self->fd < 0) {
+ PyErr_SetString(PyExc_ValueError, "File descriptor already taken");
+ return NULL;
+ }
+
+ fdnumber = Py_BuildValue("i", self->fd);
+ self->fd = -1;
+
+ return fdnumber;
+}
+
+int
+dbus_py_unix_fd_get_fd(PyObject *self)
+{
+ return ((UnixFdObject *) self)->fd;
+}
+
+static PyMethodDef UnixFd_methods[] = {
+ {"take", (PyCFunction) UnixFd_take, METH_NOARGS, UnixFd_take__doc__ },
+ {NULL}
+};
+
+PyTypeObject DBusPyUnixFd_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "dbus.UnixFd",
+ sizeof(UnixFdObject),
+ 0,
+ (destructor) UnixFd_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ UnixFd_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ UnixFd_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ UnixFd_tp_new, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_unixfd_type(void)
+{
+ if (PyType_Ready(&DBusPyUnixFd_Type) < 0) return 0;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_unixfd_type(PyObject *this_module)
+{
+ Py_INCREF(&DBusPyUnixFd_Type);
+ if (PyModule_AddObject(this_module, "UnixFd",
+ (PyObject *)&DBusPyUnixFd_Type) < 0) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/dbus_bindings/validation.c b/dbus_bindings/validation.c
new file mode 100644
index 0000000..abec0a9
--- /dev/null
+++ b/dbus_bindings/validation.c
@@ -0,0 +1,245 @@
+/* Implementation of various validation functions for use in dbus-python.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+dbus_bool_t
+dbus_py_validate_bus_name(const char *name,
+ dbus_bool_t may_be_unique,
+ dbus_bool_t may_be_not_unique)
+{
+ dbus_bool_t dot = FALSE;
+ dbus_bool_t unique;
+ char last;
+ const char *ptr;
+
+ if (name[0] == '\0') {
+ PyErr_SetString(PyExc_ValueError, "Invalid bus name: "
+ "may not be empty");
+ return FALSE;
+ }
+ unique = (name[0] == ':');
+ if (unique && !may_be_unique) {
+ PyErr_Format(PyExc_ValueError, "Invalid well-known bus name '%s':"
+ "only unique names may start with ':'", name);
+ return FALSE;
+ }
+ if (!unique && !may_be_not_unique) {
+ PyErr_Format(PyExc_ValueError, "Invalid unique bus name '%s': "
+ "unique names must start with ':'", name);
+ return FALSE;
+ }
+ if (strlen(name) > 255) {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "too long (> 255 characters)", name);
+ return FALSE;
+ }
+ last = '\0';
+ for (ptr = name + (unique ? 1 : 0); *ptr; ptr++) {
+ if (*ptr == '.') {
+ dot = TRUE;
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "contains substring '..'", name);
+ return FALSE;
+ }
+ else if (last == '\0') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "must not start with '.'", name);
+ return FALSE;
+ }
+ }
+ else if (*ptr >= '0' && *ptr <= '9') {
+ if (!unique) {
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "a digit may not follow '.' except in a "
+ "unique name starting with ':'", name);
+ return FALSE;
+ }
+ else if (last == '\0') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "must not start with a digit", name);
+ return FALSE;
+ }
+ }
+ }
+ else if ((*ptr < 'a' || *ptr > 'z') &&
+ (*ptr < 'A' || *ptr > 'Z') && *ptr != '_' && *ptr != '-') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
+ "contains invalid character '%c'", name, *ptr);
+ return FALSE;
+ }
+ last = *ptr;
+ }
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': must "
+ "not end with '.'", name);
+ return FALSE;
+ }
+ if (!dot) {
+ PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': must "
+ "contain '.'", name);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+dbus_bool_t
+dbus_py_validate_member_name(const char *name)
+{
+ const char *ptr;
+
+ if (name[0] == '\0') {
+ PyErr_SetString(PyExc_ValueError, "Invalid member name: may not "
+ "be empty");
+ return FALSE;
+ }
+ if (strlen(name) > 255) {
+ PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
+ "too long (> 255 characters)", name);
+ return FALSE;
+ }
+ for (ptr = name; *ptr; ptr++) {
+ if (*ptr >= '0' && *ptr <= '9') {
+ if (ptr == name) {
+ PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
+ "must not start with a digit", name);
+ return FALSE;
+ }
+ }
+ else if ((*ptr < 'a' || *ptr > 'z') &&
+ (*ptr < 'A' || *ptr > 'Z') && *ptr != '_') {
+ PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
+ "contains invalid character '%c'", name, *ptr);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+dbus_bool_t
+dbus_py_validate_interface_name(const char *name)
+{
+ dbus_bool_t dot = FALSE;
+ char last;
+ const char *ptr;
+
+ if (name[0] == '\0') {
+ PyErr_SetString(PyExc_ValueError, "Invalid interface or error name: "
+ "may not be empty");
+ return FALSE;
+ }
+ if (strlen(name) > 255) {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error name '%s': "
+ "too long (> 255 characters)", name);
+ return FALSE;
+ }
+ last = '\0';
+ for (ptr = name; *ptr; ptr++) {
+ if (*ptr == '.') {
+ dot = TRUE;
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or "
+ "error name '%s': contains substring '..'", name);
+ return FALSE;
+ }
+ else if (last == '\0') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error "
+ "name '%s': must not start with '.'", name);
+ return FALSE;
+ }
+ }
+ else if (*ptr >= '0' && *ptr <= '9') {
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error "
+ "name '%s': a digit may not follow '.'", name);
+ return FALSE;
+ }
+ else if (last == '\0') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error "
+ "name '%s': must not start with a digit", name);
+ return FALSE;
+ }
+ }
+ else if ((*ptr < 'a' || *ptr > 'z') &&
+ (*ptr < 'A' || *ptr > 'Z') && *ptr != '_') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error "
+ "name '%s': contains invalid character '%c'",
+ name, *ptr);
+ return FALSE;
+ }
+ last = *ptr;
+ }
+ if (last == '.') {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error name "
+ "'%s': must not end with '.'", name);
+ return FALSE;
+ }
+ if (!dot) {
+ PyErr_Format(PyExc_ValueError, "Invalid interface or error name "
+ "'%s': must contain '.'", name);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+dbus_bool_t
+dbus_py_validate_object_path(const char *path)
+{
+ const char *ptr;
+
+ if (path[0] != '/') {
+ PyErr_Format(PyExc_ValueError, "Invalid object path '%s': does not "
+ "start with '/'", path);
+ return FALSE;
+ }
+ if (path[1] == '\0') return TRUE;
+ for (ptr = path + 1; *ptr; ptr++) {
+ if (*ptr == '/') {
+ if (ptr[-1] == '/') {
+ PyErr_Format(PyExc_ValueError, "Invalid object path '%s': "
+ "contains substring '//'", path);
+ return FALSE;
+ }
+ }
+ else if ((*ptr < 'a' || *ptr > 'z') &&
+ (*ptr < 'A' || *ptr > 'Z') &&
+ (*ptr < '0' || *ptr > '9') && *ptr != '_') {
+ PyErr_Format(PyExc_ValueError, "Invalid object path '%s': "
+ "contains invalid character '%c'", path, *ptr);
+ return FALSE;
+ }
+ }
+ if (ptr[-1] == '/') {
+ PyErr_Format(PyExc_ValueError, "Invalid object path '%s': ends "
+ "with '/' and is not just '/'", path);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */