summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HACKING.txt35
-rw-r--r--_dbus_bindings/bus-impl.h415
-rw-r--r--_dbus_bindings/bytes-impl.h420
-rw-r--r--_dbus_bindings/conn-impl.h551
-rw-r--r--_dbus_bindings/conn-methods-impl.h653
-rw-r--r--_dbus_bindings/containers-impl.h743
-rw-r--r--_dbus_bindings/dbus_bindings.py27
-rw-r--r--_dbus_bindings/debug-impl.h49
-rw-r--r--_dbus_bindings/exceptions-impl.h71
-rw-r--r--_dbus_bindings/generic-impl.h108
-rw-r--r--_dbus_bindings/message-append-impl.h863
-rw-r--r--_dbus_bindings/message-get-args-impl.h403
-rw-r--r--_dbus_bindings/message-impl.h1064
-rw-r--r--_dbus_bindings/module.c139
-rw-r--r--_dbus_bindings/pending-call-impl.h230
-rw-r--r--_dbus_bindings/signature-impl.h238
-rw-r--r--_dbus_bindings/test.py30
-rw-r--r--_dbus_bindings/types-impl.h635
-rw-r--r--_dbus_bindings/validation-impl.h241
-rw-r--r--_dbus_glib_bindings/module.c74
-rw-r--r--include/dbus_bindings.h64
21 files changed, 7053 insertions, 0 deletions
diff --git a/HACKING.txt b/HACKING.txt
new file mode 100644
index 0000000..61f9d7a
--- /dev/null
+++ b/HACKING.txt
@@ -0,0 +1,35 @@
+=========================================
+D-Bus Python bindings - notes for hackers
+=========================================
+
+:Author: Simon McVittie
+:Date: 2006-09-26
+
+Code organisation
+=================
+
+Python wants everything except the init function to be declared static, so the
+whole of _dbus_bindings is a single translation unit - module.c #includes
+various files *-impl.h, which define static (sometimes static inline)
+functions. Even so, it compiles quicker than the old Pyrex implementation :-p
+
+Threading/locking model
+=======================
+
+All Python functions must be called with the GIL (obviously).
+
+Before calling into any D-Bus function that can block, release the GIL;
+as well as the usual "be nice to other threads", D-Bus does its own
+locking and we don't want to deadlock with it. Most Connection methods
+can block.
+
+Indentation and other holy wars
+===============================
+
+Python code is meant to follow PEP8, and has 4-space indentation, no hard tabs.
+
+C code is meant to follow what PEP7 as "Python 3000" style - 4-space
+indentation, no hard tabs, otherwise consistent with historical Python 2.x
+code.
+
+Docstrings etc. are reStructuredText.
diff --git a/_dbus_bindings/bus-impl.h b/_dbus_bindings/bus-impl.h
new file mode 100644
index 0000000..2864793
--- /dev/null
+++ b/_dbus_bindings/bus-impl.h
@@ -0,0 +1,415 @@
+/* Implementation of Bus, a subtype of Connection.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(Bus_tp_doc,
+"Bus([address: str or int])\n\n"
+"If the address is an int it must be one of the constants BUS_SESSION,\n"
+"BUS_SYSTEM, BUS_STARTER. The default is BUS_SESSION.\n"
+);
+
+/* Bus definition =================================================== */
+
+static PyTypeObject BusType;
+
+#define Bus_Check(ob) PyObject_TypeCheck(ob, &BusType)
+
+/* Bus methods ====================================================== */
+
+static PyObject *
+Bus_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *first = NULL;
+ DBusConnection *conn;
+ DBusError error;
+ Connection *self;
+ dbus_bool_t ret;
+ long type;
+ static char *argnames[] = {"address_or_type", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|O", argnames, &first)) {
+ return NULL;
+ }
+
+ dbus_error_init (&error);
+
+ if (first && PyString_Check(first)) {
+ /* It's a custom address. First connect to it, then register. */
+
+ self = (Connection *)Connection_tp_new(cls, args, kwargs);
+ if (!self) return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_bus_register (self->conn, &error);
+ Py_END_ALLOW_THREADS
+ if (!ret) {
+ DBusException_ConsumeError(&error);
+ Py_DECREF(self);
+ return NULL;
+ }
+ }
+
+ /* If the first argument isn't a string, it must be an integer
+ representing one of the well-known bus types. */
+
+ if (first && !PyInt_Check (first)) {
+ PyErr_SetString(PyExc_TypeError, "A string address or an integer "
+ "bus type is required");
+ return NULL;
+ }
+ if (first) {
+ type = PyInt_AsLong (first);
+ }
+ else {
+ type = DBUS_BUS_SESSION;
+ }
+
+ if (type != DBUS_BUS_SESSION && type != DBUS_BUS_SYSTEM
+ && type != DBUS_BUS_STARTER) {
+ PyErr_Format(PyExc_ValueError, "Unknown bus type %d", (int)type);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ conn = dbus_bus_get_private (type, &error);
+ Py_END_ALLOW_THREADS
+
+ if (!conn) {
+ DBusException_ConsumeError (&error);
+ return NULL;
+ }
+ return Connection_NewConsumingDBusConnection(cls, conn);
+}
+
+PyDoc_STRVAR(Bus_get_unique_name__doc__,
+"get_unique_name() -> str\n\n"
+"Return this application's unique name on this bus.\n");
+static PyObject *
+Bus_get_unique_name (Connection *self, PyObject *args)
+{
+ const char *name;
+
+ Py_BEGIN_ALLOW_THREADS
+ name = dbus_bus_get_unique_name (self->conn);
+ Py_END_ALLOW_THREADS
+ if (!name) {
+ /* shouldn't happen, but C subtypes could have done something stupid */
+ PyErr_SetString (DBusException, "Unable to retrieve unique name");
+ return NULL;
+ }
+ return PyString_FromString (name);
+}
+
+PyDoc_STRVAR(Bus_get_unix_user__doc__,
+"get_unix_user(bus_name: str) -> int\n"
+"\n"
+"Get the numeric uid of the process which owns the given bus name\n"
+"on the connected bus daemon.\n"
+"\n"
+":Parameters:\n"
+" `bus_name` : str\n"
+" A bus name (may be either a unique name or a well-known name)\n"
+);
+static PyObject *
+Bus_get_unix_user (Connection *self, PyObject *args)
+{
+ DBusError error;
+ unsigned long uid;
+ const char *bus_name;
+
+ if (!PyArg_ParseTuple(args, "s:get_unix_user", &bus_name)) {
+ return NULL;
+ }
+
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ uid = dbus_bus_get_unix_user (self->conn, bus_name, &error);
+ Py_END_ALLOW_THREADS
+ if (uid == (unsigned long)(-1)) return DBusException_ConsumeError (&error);
+ return PyLong_FromUnsignedLong (uid);
+}
+
+PyDoc_STRVAR(Bus_start_service_by_name__doc__,
+"start_service_by_name(bus_name: str) -> (True, int)\n\
+\n\
+Start a service which will implement the given bus name on this\n\
+Bus.\n\
+\n\
+:Parameters:\n\
+ `bus_name` : str\n\
+ The well-known bus name for which an implementation is required\n\
+\n\
+:Returns: A tuple of 2 elements. The first is always True, the second is\n\
+ either START_REPLY_SUCCESS or START_REPLY_ALREADY_RUNNING.\n\
+\n\
+:Raises DBusException: if the service could not be started.\n\
+\n\
+FIXME: Fix return signature?\n\
+");
+static PyObject *
+Bus_start_service_by_name (Connection *self, PyObject *args)
+{
+ DBusError error;
+ const char *bus_name;
+ dbus_uint32_t ret;
+ dbus_bool_t success;
+
+ if (!PyArg_ParseTuple(args, "s:start_service_by_name", &bus_name)) {
+ return NULL;
+ }
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ success = dbus_bus_start_service_by_name (self->conn, bus_name,
+ 0 /* flags */, &ret, &error);
+ Py_END_ALLOW_THREADS
+ if (!success) {
+ return DBusException_ConsumeError (&error);
+ }
+ return Py_BuildValue ("(Ol)", Py_True, (long)ret);
+}
+
+/* FIXME: signal IN_QUEUE, EXISTS by exception? */
+PyDoc_STRVAR(Bus_request_name__doc__, "");
+static PyObject *
+Bus_request_name (Connection *self, PyObject *args)
+{
+ unsigned int flags = 0;
+ const char *bus_name;
+ int ret;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "s|I:request_name", &bus_name, &flags)) {
+ return NULL;
+ }
+ if (!_validate_bus_name(bus_name, 0, 1)) return NULL;
+
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_bus_request_name(self->conn, bus_name, flags, &error);
+ Py_END_ALLOW_THREADS
+ if (ret == -1) return DBusException_ConsumeError (&error);
+
+ return PyInt_FromLong(ret);
+}
+
+PyDoc_STRVAR(Bus_release_name__doc__, "");
+static PyObject *
+Bus_release_name (Connection *self, PyObject *args)
+{
+ const char *bus_name;
+ int ret;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "s:release_name", &bus_name)) return NULL;
+
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_bus_release_name(self->conn, bus_name, &error);
+ Py_END_ALLOW_THREADS
+ if (ret == -1) return DBusException_ConsumeError (&error);
+
+ return PyInt_FromLong(ret);
+}
+
+PyDoc_STRVAR (Bus_name_has_owner__doc__,
+"name_has_owner(bus_name: str) -> bool\n\n"
+"Return True if and only if the given bus name has an owner on this bus.\n");
+static PyObject *
+Bus_name_has_owner (Connection *self, PyObject *args)
+{
+ const char *bus_name;
+ int ret;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "s:name_has_owner", &bus_name)) return NULL;
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_bus_name_has_owner(self->conn, bus_name, &error);
+ Py_END_ALLOW_THREADS
+ if (dbus_error_is_set (&error)) {
+ return DBusException_ConsumeError (&error);
+ }
+ return PyBool_FromLong(ret);
+}
+
+PyDoc_STRVAR (Bus_add_match_string__doc__,
+"add_match_string(rule: str)\n\n"
+"Arrange for this application to receive messages on the bus that match\n"
+"the given rule. This version will block and raises DBusException on error.\n");
+static PyObject *
+Bus_add_match_string (Connection *self, PyObject *args)
+{
+ const char *rule;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "s:add_match", &rule)) return NULL;
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_bus_add_match (self->conn, rule, &error);
+ Py_END_ALLOW_THREADS
+ if (dbus_error_is_set (&error)) {
+ return DBusException_ConsumeError (&error);
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR (Bus_add_match_string_non_blocking__doc__,
+"add_match_string_non_blocking(rule: str)\n\n"
+"Arrange for this application to receive messages on the bus that match\n"
+"the given rule. This version does not block, but any errors will be\n"
+"ignored.\n");
+static PyObject *
+Bus_add_match_string_non_blocking (Connection *self, PyObject *args)
+{
+ const char *rule;
+
+ if (!PyArg_ParseTuple(args, "s:add_match", &rule)) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ dbus_bus_add_match (self->conn, rule, NULL);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR (Bus_remove_match_string__doc__,
+"remove_match_string_non_blocking(rule: str)\n\n"
+"Remove the given match rule; if it has been added more than once,\n"
+"remove one of the identical copies, leaving the others active.\n"
+"This version blocks, and raises DBusException on error.\n");
+static PyObject *
+Bus_remove_match_string (Connection *self, PyObject *args)
+{
+ const char *rule;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "s:remove_match", &rule)) return NULL;
+ dbus_error_init (&error);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_bus_remove_match (self->conn, rule, &error);
+ Py_END_ALLOW_THREADS
+ if (dbus_error_is_set (&error)) {
+ return DBusException_ConsumeError (&error);
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR (Bus_remove_match_string_non_blocking__doc__,
+"remove_match_string_non_blocking(rule: str)\n\n"
+"Remove the given match rule; if it has been added more than once,\n"
+"remove one of the identical copies, leaving the others active.\n"
+"This version does not block, but causes any errors to be ignored.\n");
+static PyObject *
+Bus_remove_match_string_non_blocking (Connection *self, PyObject *args)
+{
+ const char *rule;
+
+ if (!PyArg_ParseTuple(args, "s:remove_match", &rule)) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ dbus_bus_remove_match (self->conn, rule, NULL);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+/* Bus type object ================================================== */
+
+static struct PyMethodDef Bus_tp_methods[] = {
+#define ENTRY(name, flags) {#name, (PyCFunction)Bus_##name, flags, Bus_##name##__doc__},
+ ENTRY(get_unique_name, METH_NOARGS)
+ ENTRY(get_unix_user, METH_VARARGS)
+ ENTRY(start_service_by_name, METH_VARARGS)
+ ENTRY(request_name, METH_VARARGS)
+ ENTRY(release_name, METH_VARARGS)
+ ENTRY(name_has_owner, METH_VARARGS)
+ ENTRY(name_has_owner, METH_VARARGS)
+ ENTRY(add_match_string, METH_VARARGS)
+ ENTRY(add_match_string_non_blocking, METH_VARARGS)
+ ENTRY(remove_match_string, METH_VARARGS)
+ ENTRY(remove_match_string_non_blocking, METH_VARARGS)
+#undef ENTRY
+ {NULL},
+};
+
+/* TODO: Call this dbus.Bus rather than _dbus_bindings._Bus if it ever gets
+ * all the functionality of the current dbus._dbus.Bus (mainly creation of
+ * proxies).
+ */
+static PyTypeObject BusType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings._Bus", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)Connection_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*/
+ Bus_tp_doc, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ Bus_tp_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ &ConnectionType, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ 0, /*tp_init*/
+ 0, /*tp_alloc*/
+ Bus_tp_new, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+};
+
+static inline int
+init_bus_types (void)
+{
+ if (PyType_Ready (&BusType) < 0) return 0;
+ return 1;
+}
+
+static inline int
+insert_bus_types (PyObject *this_module)
+{
+ if (PyModule_AddObject (this_module, "_Bus",
+ (PyObject *)&BusType) < 0) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/bytes-impl.h b/_dbus_bindings/bytes-impl.h
new file mode 100644
index 0000000..c9753a3
--- /dev/null
+++ b/_dbus_bindings/bytes-impl.h
@@ -0,0 +1,420 @@
+/* D-Bus Byte and ByteArray types.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+static PyTypeObject ByteType, ByteArrayType;
+
+static inline int Byte_Check(PyObject *o)
+{
+ return (o->ob_type == &ByteType)
+ || PyObject_IsInstance(o, (PyObject *)&ByteType);
+}
+
+static inline int ByteArray_Check(PyObject *o)
+{
+ return (o->ob_type == &ByteArrayType)
+ || PyObject_IsInstance(o, (PyObject *)&ByteArrayType);
+}
+
+PyDoc_STRVAR(Byte_tp_doc,
+"Byte(integer or str of length 1)\n"
+"\n"
+"Byte is a subtype of str, restricted to length exactly 1.\n"
+"\n"
+"A Byte b also supports the following operations:\n"
+"\n"
+"* int(b) == long(b) == float(b) == ord(b)\n"
+"\n"
+"* oct(b), hex(b)\n"
+);
+
+static inline unsigned char
+Byte_as_uchar(PyObject *self)
+{
+ return (unsigned char) (PyString_AS_STRING (self)[0]);
+}
+
+PyObject *allocated_bytes[256] = {NULL};
+
+static PyObject *
+Byte_from_uchar(unsigned char data)
+{
+ PyObject *ret;
+ ret = allocated_bytes[data];
+ if (!ret) {
+ char c[] = { (char)data, '\0' };
+ PyObject *tuple = Py_BuildValue("(s#)", c, 1);
+ DBG("Allocating a new Byte of value \\x%02x", data);
+
+ if (!tuple) return NULL;
+
+ ret = PyString_Type.tp_new(&ByteType, tuple, NULL);
+ Py_DECREF(tuple);
+ tuple = NULL;
+
+#ifdef USING_DBG
+ fprintf(stderr, "New Byte of value \\x%02x: ", data);
+ PyObject_Print(ret, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ Py_INCREF(ret);
+ allocated_bytes[data] = ret;
+ }
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *
+Byte_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *arg;
+ PyObject *string;
+ PyObject *tuple;
+
+ if (PyTuple_Size(args) != 1 || (kwargs && PyDict_Size(kwargs) != 0)) {
+ PyErr_SetString(PyExc_TypeError, "Byte constructor takes exactly one "
+ "positional argument");
+ return NULL;
+ }
+
+ /* arg is only a borrowed ref for the moment */
+ arg = PyTuple_GetItem(args, 0);
+
+ if (PyString_Check(arg)) {
+ /* string of length 1, we hope */
+ if (PyString_GET_SIZE(arg) != 1) {
+ goto bad_arg;
+ }
+ if (arg->ob_type == &ByteType) {
+ Py_INCREF(arg);
+ return arg;
+ }
+ if (cls == &ByteType) {
+ /* we know that the Byte type is the same as a string
+ * internally, so fast-track it */
+ return Byte_from_uchar((unsigned char)(PyString_AS_STRING(arg)[0]));
+ }
+ /* only a borrowed reference so far, take ownership */
+ Py_INCREF(arg);
+ }
+ else if (PyInt_Check(arg)) {
+ long i = PyInt_AS_LONG(arg);
+
+ if (i < 0 || i > 255) goto bad_range;
+ /* make a byte object, which is a length-1 string - now it's a new
+ reference */
+ arg = Byte_from_uchar((unsigned char)i);
+ if (!arg) return NULL;
+ /* if that's the type we wanted, there's nothing more to do */
+ if (cls == &ByteType) return arg;
+ }
+ else {
+ goto bad_arg;
+ }
+
+ /* so here's the complicated case: we're trying to instantiate a subclass
+ so we can't just allocate a Byte and go "it'll all be fine".
+
+ By now, we do have a string-of-length-1 to use as an argument to the c'tor
+ */
+ tuple = Py_BuildValue("(O)", arg);
+ if (!tuple) return NULL;
+ Py_DECREF(arg);
+ arg = NULL;
+
+ string = PyString_Type.tp_new(cls, tuple, NULL);
+ Py_DECREF(tuple);
+ tuple = NULL;
+ return string;
+
+bad_arg:
+ PyErr_SetString(PyExc_TypeError, "Expected a string 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_nb_int (PyObject *self)
+{
+ return PyInt_FromLong(Byte_as_uchar(self));
+}
+
+static PyObject *Byte_nb_float (PyObject *self)
+{
+ return PyFloat_FromDouble(Byte_as_uchar(self));
+}
+
+static PyObject *Byte_nb_long (PyObject *self)
+{
+ return PyLong_FromLong(Byte_as_uchar(self));
+}
+
+static PyObject *Byte_nb_oct (PyObject *self)
+{
+ PyObject *i = PyInt_FromLong(Byte_as_uchar(self));
+ if (!i) return NULL;
+ PyObject *s = (i->ob_type->tp_as_number->nb_oct) (i);
+ Py_XDECREF (i);
+ return s;
+}
+
+static PyObject *Byte_nb_hex (PyObject *self)
+{
+ PyObject *i = PyInt_FromLong(Byte_as_uchar(self));
+ if (!i) return NULL;
+ PyObject *s = (i->ob_type->tp_as_number->nb_hex) (i);
+ Py_XDECREF (i);
+ return s;
+}
+
+static PyNumberMethods Byte_tp_as_number = {
+ 0, /* nb_add */
+ 0, /* nb_subtract */
+ 0, /* nb_multiply */
+ 0, /* nb_divide */
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+ 0, /* nb_nonzero */
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ 0, /* nb_or */
+ 0, /* nb_coerce */
+ (unaryfunc)Byte_nb_int, /* nb_int */
+ (unaryfunc)Byte_nb_long, /* nb_long */
+ (unaryfunc)Byte_nb_float, /* nb_float */
+ (unaryfunc)Byte_nb_oct, /* nb_oct */
+ (unaryfunc)Byte_nb_hex, /* nb_hex */
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+ 0, /* nb_inplace_divide */
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ 0, /* nb_floor_divide */
+ 0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+};
+
+static PyTypeObject ByteType = {
+ PyObject_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 */
+ str_subclass_tp_repr, /* tp_repr */
+ &Byte_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 */
+ 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(&PyString_Type), /* 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 */
+};
+
+PyDoc_STRVAR(ByteArray_tp_doc,
+"ByteArray(str)\n"
+"\n"
+"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"
+"The subscript operation byte_array[i] returns Byte instances. Otherwise,\n"
+"it's just a string.\n"
+);
+
+static inline unsigned char *
+ByteArray_as_ucharptr(PyObject *self)
+{
+ return (unsigned char *)PyString_AsString(self);
+}
+
+static inline PyObject *
+ByteArray_from_uchars(const unsigned char *data, int size)
+{
+ return PyObject_CallFunction((PyObject *)&ByteArrayType, "(s#)",
+ (char *)data, size);
+}
+
+static PyObject *
+ByteArray_sq_item (PyObject *self, int i)
+{
+ unsigned char c;
+ if (i < 0 || i >= PyString_GET_SIZE(self)) {
+ PyErr_SetString(PyExc_IndexError, "ByteArray index out of range");
+ return NULL;
+ }
+ c = ((unsigned char *)PyString_AS_STRING(self))[i];
+ return Byte_from_uchar(c);
+}
+
+static PyObject *
+ByteArray_mp_subscript(PyObject *self, PyObject *other)
+{
+ long i;
+ if (PyInt_Check(other)) {
+ i = PyInt_AS_LONG(other);
+ if (i < 0) i += PyString_GET_SIZE (self);
+ return ByteArray_sq_item(self, i);
+ }
+ else if (PyLong_Check(other)) {
+ i = PyLong_AsLong(other);
+ if (i == -1 && PyErr_Occurred()) return NULL;
+ if (i < 0) i += PyString_GET_SIZE(self);
+ return ByteArray_sq_item(self, i);
+ }
+ else {
+ /* slices just return strings */
+ return (PyString_Type.tp_as_mapping->mp_subscript)(self, other);
+ }
+}
+
+static PyMappingMethods ByteArray_tp_as_mapping = {
+ 0, /* mp_length */
+ ByteArray_mp_subscript, /* mp_subscript */
+ 0, /* mp_ass_subscript */
+};
+
+static PySequenceMethods ByteArray_tp_as_sequence = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ ByteArray_sq_item, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ 0, /* sq_contains */
+};
+
+static PyTypeObject ByteArrayType = {
+ PyObject_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 */
+ str_subclass_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ &ByteArray_tp_as_sequence, /* tp_as_sequence */
+ &ByteArray_tp_as_mapping, /* 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(&PyString_Type), /* 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 */
+};
+
+static inline int
+init_byte_types(void)
+{
+ ByteType.tp_base = &PyString_Type;
+ if (PyType_Ready(&ByteType) < 0) return 0;
+ /* disable the tp_print copied from PyString_Type, so tp_repr gets called as
+ desired */
+ ByteType.tp_print = NULL;
+
+ ByteArrayType.tp_base = &PyString_Type;
+ if (PyType_Ready(&ByteArrayType) < 0) return 0;
+ ByteArrayType.tp_print = NULL;
+
+ return 1;
+}
+
+static inline int
+insert_byte_types(PyObject *this_module)
+{
+ Py_INCREF(&ByteType);
+ if (PyModule_AddObject(this_module, "Byte",
+ (PyObject *)&ByteType) < 0) return 0;
+ Py_INCREF(&ByteArrayType);
+ if (PyModule_AddObject(this_module, "ByteArray",
+ (PyObject *)&ByteArrayType) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/conn-impl.h b/_dbus_bindings/conn-impl.h
new file mode 100644
index 0000000..daf146f
--- /dev/null
+++ b/_dbus_bindings/conn-impl.h
@@ -0,0 +1,551 @@
+/* Implementation of the _dbus_bindings Connection type, a Python wrapper
+ * for DBusConnection. See also conn-methods-impl.h.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Connection definition ============================================ */
+
+PyDoc_STRVAR(Connection_tp_doc,
+"Connection(address: str)\n\n"
+);
+
+typedef struct Connection {
+ 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;
+
+ PyObject *weaklist;
+} Connection;
+
+static PyTypeObject ConnectionType;
+
+static inline int Connection_Check(PyObject *o)
+{
+ return PyObject_TypeCheck(o, &ConnectionType);
+}
+
+/* Helpers ========================================================== */
+
+static PyObject *Connection_ExistingFromDBusConnection(DBusConnection *);
+static PyObject *Connection_GetObjectPathHandlers(Connection *, PyObject *);
+static DBusHandlerResult Connection_HandleMessage(Connection *, Message *,
+ PyObject *);
+
+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 *)Connection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) goto out;
+
+ DBG("Connection at %p unregistering object path %s",
+ conn_obj, PyString_AS_STRING((PyObject *)user_data));
+ tuple = Connection_GetObjectPathHandlers(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_XDECREF(conn_obj);
+ Py_XDECREF(tuple);
+ /* the user_data (a Python str) is no longer ref'd by the DBusConnection */
+ Py_XDECREF((PyObject *)user_data);
+ 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;
+ Message *msg_obj;
+ PyObject *callable; /* borrowed */
+
+ dbus_message_ref(message);
+ msg_obj = (Message *)Message_ConsumeDBusMessage(message);
+ if (!msg_obj) {
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto out;
+ }
+
+ conn_obj = (Connection *)Connection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) {
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+
+ DBG("Connection at %p messaging object path %s",
+ conn_obj, PyString_AS_STRING((PyObject *)user_data));
+ DBG_DUMP_MESSAGE(message);
+ tuple = Connection_GetObjectPathHandlers(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 = Connection_HandleMessage(conn_obj, msg_obj, callable);
+ }
+
+out:
+ Py_XDECREF(msg_obj);
+ Py_XDECREF(conn_obj);
+ Py_XDECREF(tuple);
+ 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;
+ Message *msg_obj;
+#ifndef DBUS_PYTHON_DISABLE_CHECKS
+ int i, size;
+#endif
+
+ dbus_message_ref(message);
+ msg_obj = (Message *)Message_ConsumeDBusMessage(message);
+ if (!msg_obj) {
+ DBG("%s", "OOM while trying to construct Message");
+ ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto out;
+ }
+
+ conn_obj = (Connection *)Connection_ExistingFromDBusConnection(conn);
+ if (!conn_obj) {
+ DBG("%s", "failed to traverse DBusConnection -> Connection weakref");
+ ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
+
+ /* 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);
+ }
+ 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 = Connection_HandleMessage(conn_obj, msg_obj, callable);
+out:
+ Py_XDECREF(msg_obj);
+ Py_XDECREF(conn_obj);
+ Py_XDECREF(callable);
+ PyGILState_Release(gil);
+ return ret;
+}
+
+/* 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. */
+static DBusConnection *
+Connection_BorrowDBusConnection(PyObject *self)
+{
+ if (!Connection_Check(self)) {
+ PyErr_SetString(PyExc_TypeError, "A dbus.Connection is required");
+ return NULL;
+ }
+ return ((Connection *)self)->conn;
+}
+
+/* Internal C API =================================================== */
+
+/* Pass a message through a handler. */
+static DBusHandlerResult
+Connection_HandleMessage(Connection *conn, Message *msg, PyObject *callable)
+{
+ PyObject *obj = PyObject_CallFunctionObjArgs(callable, conn, msg,
+ NULL);
+ if (obj == Py_None) {
+ DBG("%p: OK, handler %p returned None", conn, callable);
+ Py_DECREF(obj);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (obj == Py_NotImplemented) {
+ DBG("%p: handler %p returned NotImplemented, continuing",
+ conn, callable);
+ Py_DECREF(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 = PyInt_AsLong(obj);
+ DBG("%p: handler %p returned %ld", conn, callable, i);
+ Py_DECREF(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. */
+static PyObject *
+Connection_GetObjectPathHandlers(Connection *self, PyObject *path)
+{
+ PyObject *callbacks = PyDict_GetItem(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.
+ */
+static PyObject *
+Connection_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) {
+ self = PyWeakref_GetObject(ref); /* still a borrowed ref */
+ if (self && self != Py_None && Connection_Check(self)) {
+ Py_INCREF(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 *
+Connection_NewConsumingDBusConnection(PyTypeObject *cls, DBusConnection *conn)
+{
+ Connection *self;
+ PyObject *ref;
+ dbus_bool_t ok;
+
+ 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");
+ return NULL;
+ }
+ }
+ ref = NULL;
+
+ DBG("Constructing Connection from DBusConnection at %p", conn);
+
+ self = (Connection *)(cls->tp_alloc(cls, 0));
+ if (!self) goto err;
+
+ self->conn = NULL;
+ self->filters = PyList_New(0);
+ 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;
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_set_data(conn, _connection_python_slot,
+ (void *)ref,
+ (DBusFreeFunction)Glue_TakeGILAndXDecref);
+ Py_END_ALLOW_THREADS
+
+ if (!ok) {
+ PyErr_NoMemory();
+ goto err;
+ }
+
+ self->conn = conn;
+
+ return (PyObject *)self;
+
+err:
+ DBG("Failed to construct Connection from DBusConnection at %p", conn);
+ Py_XDECREF(self);
+ Py_XDECREF(ref);
+ if (conn) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ Py_END_ALLOW_THREADS
+ }
+ return NULL;
+}
+
+/* Connection type-methods ========================================== */
+
+/* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
+ * to which this delegates). */
+static PyObject *
+Connection_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ DBusConnection *conn;
+ const char *address;
+ DBusError error;
+ PyObject *self;
+ static char *argnames[] = {"address", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", argnames, &address)) {
+ return NULL;
+ }
+
+ 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) {
+ DBusException_ConsumeError(&error);
+ return NULL;
+ }
+ self = Connection_NewConsumingDBusConnection(cls, conn);
+
+ return self;
+}
+
+/* Destructor */
+static void Connection_tp_dealloc(Connection *self)
+{
+ DBusConnection *conn = self->conn;
+ self->conn = NULL;
+
+ DBG("Deallocating Connection at %p (DBusConnection at %p)", self, conn);
+
+ if (conn) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_close(conn);
+ Py_END_ALLOW_THREADS
+
+ dbus_connection_unref(conn);
+ }
+
+ Py_XDECREF(self->filters);
+ Py_XDECREF(self->object_paths);
+ (self->ob_type->tp_free)((PyObject *)self);
+}
+
+/* Connection_tp_methods */
+#include "conn-methods-impl.h"
+
+/* Connection type object =========================================== */
+
+static PyTypeObject ConnectionType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_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*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE,
+ 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*/
+ Connection_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*/
+ Connection_tp_new, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+};
+
+static inline dbus_bool_t
+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 0;
+ }
+
+ ConnectionType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&ConnectionType) < 0) return 0;
+ return 1;
+}
+
+static inline dbus_bool_t
+insert_conn_types(PyObject *this_module)
+{
+ PyObject *c_api;
+ static void *dbus_bindings_API[1];
+
+ dbus_bindings_API[0] = (void *)Connection_BorrowDBusConnection;
+ c_api = PyCObject_FromVoidPtr ((void *)dbus_bindings_API, NULL);
+ if (c_api) {
+ PyModule_AddObject(this_module, "_C_API", c_api);
+ }
+
+ if (PyModule_AddObject(this_module, "Connection",
+ (PyObject *)&ConnectionType) < 0) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/conn-methods-impl.h b/_dbus_bindings/conn-methods-impl.h
new file mode 100644
index 0000000..f5b2125
--- /dev/null
+++ b/_dbus_bindings/conn-methods-impl.h
@@ -0,0 +1,653 @@
+/* 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/>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(Connection_close__doc__,
+"close()\n\n"
+"Close the connection.");
+static PyObject *
+Connection_close (Connection *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ":close")) return NULL;
+ /* 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)
+{
+ dbus_bool_t ret;
+ if (!PyArg_ParseTuple(args, ":get_is_connected")) return NULL;
+ 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)
+{
+ dbus_bool_t ret;
+ if (!PyArg_ParseTuple(args, ":get_is_authenticated")) return NULL;
+ 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;
+ 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__doc__,
+"_send(msg: Message) -> long\n\n"
+"Queue the given message for sending, and return the message serial number.\n"
+);
+static PyObject *
+Connection__send (Connection *self, PyObject *args)
+{
+ dbus_bool_t ok;
+ PyObject *obj;
+ DBusMessage *msg;
+ dbus_uint32_t serial;
+
+ if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
+
+ msg = Message_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);
+}
+
+/* The timeout is in seconds here, since that's conventional in Python. */
+PyDoc_STRVAR(Connection__send_with_reply__doc__,
+"_send_with_reply(msg: Message, reply_handler: callable[, timeout_s: float])"
+" -> PendingCall\n\n"
+"Queue the message for sending; expect a reply via the returned PendingCall.\n"
+"\n"
+":Parameters:\n"
+" `msg` : 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"
+":Returns\n"
+" A `PendingCall` instance which can be used to cancel the pending call.\n"
+"\n"
+);
+static PyObject *
+Connection__send_with_reply(Connection *self, PyObject *args)
+{
+ dbus_bool_t ok;
+ double timeout_s = -1.0;
+ int timeout_ms;
+ PyObject *obj, *callable;
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+
+ if (!PyArg_ParseTuple(args, "OO|f:send_with_reply", &obj, &callable,
+ &timeout_s)) {
+ return NULL;
+ }
+
+ msg = Message_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();
+ }
+
+ return PendingCall_ConsumeDBusPendingCall(pending, callable);
+}
+
+/* Again, the timeout is in seconds, since that's conventional in Python. */
+PyDoc_STRVAR(Connection__send_with_reply_and_block__doc__,
+"_send_with_reply_and_block(msg: Message, [, timeout_s: float])"
+" -> 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` : 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 `Message` instance (probably a `MethodReturnMessage`) on success\n"
+":Raises\n"
+" A `DBusException` on error (including if the reply arrives but is an\n"
+" error message)\n"
+"\n"
+);
+static PyObject *
+Connection__send_with_reply_and_block(Connection *self, PyObject *args)
+{
+ double timeout_s = -1.0;
+ int timeout_ms;
+ PyObject *obj;
+ DBusMessage *msg, *reply;
+ DBusError error;
+
+ if (!PyArg_ParseTuple(args, "O|f:_send_with_reply_and_block", &obj,
+ &timeout_s)) {
+ return NULL;
+ }
+
+ msg = Message_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
+
+ if (!reply) {
+ return DBusException_ConsumeError(&error);
+ }
+ return Message_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)
+{
+ 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)
+{
+ int fd;
+ dbus_bool_t ok;
+
+ Py_BEGIN_ALLOW_THREADS
+ ok = dbus_connection_get_unix_fd (self->conn, &fd);
+ Py_END_ALLOW_THREADS
+ if (!ok) Py_RETURN_NONE;
+ return PyInt_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)
+{
+ unsigned long uid;
+ dbus_bool_t ok;
+
+ 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)
+{
+ unsigned long pid;
+ dbus_bool_t ok;
+
+ 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_filter__doc__,
+"_add_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 with `_register_object_path`.\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_filter(Connection *self, PyObject *callable)
+{
+ dbus_bool_t ok;
+
+ /* 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_filter__doc__,
+"_remove_filter(callable)\n\n"
+"Remove the given message filter (see `_add_filter` for details).\n");
+static PyObject *
+Connection__remove_filter(Connection *self, PyObject *callable)
+{
+ PyObject *obj;
+
+ /* 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_DECREF(obj);
+
+ Py_BEGIN_ALLOW_THREADS
+ dbus_connection_remove_filter(self->conn, _filter_message, callable);
+ Py_END_ALLOW_THREADS
+
+ Py_RETURN_NONE;
+}
+
+/* object exports not yet implemented: */
+
+PyDoc_STRVAR(Connection__register_object_path__doc__,
+"_register_object_path(path: str, on_message: callable[, on_unregister: "
+"callable][, **kwargs])\n\n"
+"Keyword arguments accepted:\n"
+"fallback: bool (default False): if True, when a message arrives for a\n"
+"'subdirectory' of the given path and there is no more specific handler,\n"
+"use this handler. Normally this handler is only run if the paths match\n"
+"exactly.\n"
+);
+static PyObject *
+Connection__register_object_path(Connection *self, PyObject *args,
+ PyObject *kwargs)
+{
+ dbus_bool_t ok;
+ int fallback = 0;
+ PyObject *callbacks, *path, *tuple, *on_message, *on_unregister = Py_None;
+ static char *argnames[] = {"path", "on_message", "on_unregister",
+ "fallback", 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.
+ We make an exception for ObjectPaths because they're equally simple,
+ are known to have the same __eq__ and __hash__, and are what calling code
+ ought to be using. */
+ if (PyString_CheckExact(path) || path->ob_type == &ObjectPathType) {
+ Py_INCREF(path);
+ }
+ else if (PyUnicode_Check(path)) {
+ path = PyUnicode_AsUTF8String(path);
+ if (!path) return NULL;
+ }
+ else if (PyString_Check(path)) {
+ path = PyString_FromString(PyString_AS_STRING(path));
+ if (!path) return NULL;
+ }
+
+ if (!_validate_object_path(PyString_AS_STRING(path))) {
+ Py_DECREF(path);
+ return NULL;
+ }
+
+ tuple = Py_BuildValue("(OO)", on_unregister, on_message);
+ if (!tuple) {
+ Py_DECREF(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",
+ PyString_AS_STRING(path));
+ Py_DECREF(tuple);
+ Py_DECREF(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_DECREF(tuple);
+ Py_DECREF(path);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ if (fallback) {
+ ok = dbus_connection_register_fallback(self->conn,
+ PyString_AS_STRING(path),
+ &_object_path_vtable,
+ path);
+ }
+ else {
+ ok = dbus_connection_register_object_path(self->conn,
+ PyString_AS_STRING(path),
+ &_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,
+ PyString_AS_STRING(path));
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+ /* don't DECREF path: libdbus owns a ref now */
+ Py_DECREF(tuple);
+ Py_RETURN_NONE;
+ }
+ else {
+ /* Oops, OOM. Tidy up, if we can, ignoring any error. */
+ PyDict_DelItem(self->object_paths, path);
+ PyErr_Clear();
+ Py_DECREF(tuple);
+ Py_DECREF(path);
+ PyErr_NoMemory();
+ return NULL;
+ }
+}
+
+PyDoc_STRVAR(Connection__unregister_object_path__doc__,
+"_unregister_object_path(path: str)\n\n"
+""
+);
+static PyObject *
+Connection__unregister_object_path(Connection *self, PyObject *args,
+ PyObject *kwargs)
+{
+ dbus_bool_t ok;
+ PyObject *path;
+ PyObject *callbacks;
+ static char *argnames[] = {"path", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O!:_unregister_object_path",
+ argnames,
+ &PyString_Type, &path)) return NULL;
+
+ /* Take a ref to the path. Same comments as for _register_object_path. */
+ if (PyString_CheckExact(path) || path->ob_type == &ObjectPathType) {
+ Py_INCREF(path);
+ }
+ else {
+ path = PyString_FromString(PyString_AS_STRING(path));
+ if (!path) return NULL;
+ }
+
+ /* 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",
+ PyString_AS_STRING(path));
+ Py_DECREF(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_DECREF(callbacks);
+ Py_DECREF(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,
+ PyString_AS_STRING(path));
+ Py_END_ALLOW_THREADS
+
+ if (ok) {
+ Py_DECREF(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_DECREF(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_DECREF(path);
+ Py_DECREF(callbacks);
+ return PyErr_NoMemory();
+ }
+}
+
+ /* dbus_connection_get_object_path_data - not useful to Python,
+ * the object path data is just a PyString 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 */
+
+static struct PyMethodDef Connection_tp_methods[] = {
+#define ENTRY(name, flags) {#name, (PyCFunction)Connection_##name, flags, Connection_##name##__doc__}
+ 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_filter, METH_O),
+ ENTRY(_register_object_path, METH_VARARGS|METH_KEYWORDS),
+ ENTRY(_remove_filter, METH_O),
+ ENTRY(_send, METH_VARARGS),
+ ENTRY(_send_with_reply, METH_VARARGS),
+ ENTRY(_send_with_reply_and_block, METH_VARARGS),
+ ENTRY(_unregister_object_path, METH_VARARGS|METH_KEYWORDS),
+ {NULL},
+#undef ENTRY
+};
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/containers-impl.h b/_dbus_bindings/containers-impl.h
new file mode 100644
index 0000000..d0d8a1a
--- /dev/null
+++ b/_dbus_bindings/containers-impl.h
@@ -0,0 +1,743 @@
+/* D-Bus container types: Variant, Array and Dict.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdint.h>
+
+/* IntNN, UIntNN ==================================================== */
+
+static PyTypeObject VariantType, ArrayType, DictType;
+
+#define DEFINE_CHECK(type) \
+static inline int type##_Check (PyObject *o) \
+{ \
+ return (o->ob_type == &type##Type) \
+ || PyObject_IsInstance(o, (PyObject *)&type##Type); \
+}
+DEFINE_CHECK(Variant)
+DEFINE_CHECK(Array)
+DEFINE_CHECK(Dict)
+#undef DEFINE_CHECK
+
+PyDoc_STRVAR(Array_tp_doc,
+"Array([iterable, ][signature=Signature(...)])\n\n"
+"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 may change in future so validation is done earlier.\n"
+"\n"
+"The signature may be None, in which case when the Array is sent over\n"
+"D-Bus, the item signature will be guessed from the first element.\n");
+
+typedef struct {
+ PyListObject super;
+ PyObject *signature;
+} Array;
+
+static struct PyMemberDef Array_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(Array, signature), READONLY,
+ "The D-Bus signature of each element of this Array (a Signature "
+ "instance)"},
+ {NULL},
+};
+
+static void
+Array_tp_dealloc (Array *self)
+{
+ Py_XDECREF(self->signature);
+ self->signature = NULL;
+ (PyList_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Array_tp_repr(Array *self)
+{
+ PyObject *parent_repr = (PyList_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ my_repr = PyString_FromFormat("%s(%s, signature=%s)",
+ self->super.ob_type->tp_name,
+ PyString_AS_STRING(parent_repr),
+ PyString_AS_STRING(sig_repr));
+finally:
+ Py_XDECREF(parent_repr);
+ Py_XDECREF(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Array_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ Array *self = (Array *)(PyList_Type.tp_new)(cls, args, kwargs);
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ return (PyObject *)self;
+}
+
+static int
+Array_tp_init (Array *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ static char *argnames[] = {"iterable", "signature", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:__init__", argnames,
+ &obj, &signature)) {
+ 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 *)&SignatureType)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&SignatureType, "(O)",
+ signature);
+ if (!signature) return -1;
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_DECREF(signature);
+ return -1;
+ }
+ if ((PyList_Type.tp_init)((PyObject *)self, tuple, NULL) < 0) {
+ Py_DECREF(tuple);
+ Py_DECREF(signature);
+ return -1;
+ }
+ Py_DECREF(tuple);
+
+ Py_XDECREF(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+static PyTypeObject ArrayType = {
+ PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+ 0,
+ "dbus.Array",
+ sizeof(Array),
+ 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 */
+};
+
+PyDoc_STRVAR(Dict_tp_doc,
+"Dictionary([mapping_or_iterable, ][signature=Signature(...)])\n\n"
+"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"
+"The signature may be None, in which case when the Dictionary is sent over\n"
+"D-Bus, the key and value signatures will be guessed from some arbitrary.\n"
+"element.\n");
+
+typedef struct {
+ PyDictObject super;
+ PyObject *signature;
+} Dict;
+
+static struct PyMemberDef Dict_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(Dict, 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."},
+ {NULL},
+};
+
+static void
+Dict_tp_dealloc (Dict *self)
+{
+ Py_XDECREF(self->signature);
+ self->signature = NULL;
+ (PyDict_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Dict_tp_repr(Dict *self)
+{
+ PyObject *parent_repr = (PyDict_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ my_repr = PyString_FromFormat("%s(%s, signature=%s)",
+ self->super.ob_type->tp_name,
+ PyString_AS_STRING(parent_repr),
+ PyString_AS_STRING(sig_repr));
+finally:
+ Py_XDECREF(parent_repr);
+ Py_XDECREF(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Dict_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ Dict *self = (Dict *)(PyDict_Type.tp_new)(cls, args, kwargs);
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ return (PyObject *)self;
+}
+
+static int
+Dict_tp_init(Dict *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ static char *argnames[] = {"mapping_or_iterable", "signature", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:__init__", argnames,
+ &obj, &signature)) {
+ 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 *)&SignatureType)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&SignatureType, "(O)",
+ signature);
+ if (!signature) return -1;
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_DECREF(signature);
+ return -1;
+ }
+
+ if ((PyDict_Type.tp_init((PyObject *)self, tuple, NULL)) < 0) {
+ Py_DECREF(tuple);
+ Py_DECREF(signature);
+ return -1;
+ }
+ Py_DECREF(tuple);
+
+ Py_XDECREF(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+static PyTypeObject DictType = {
+ PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+ 0,
+ "dbus.Dictionary",
+ sizeof(Dict),
+ 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 */
+};
+
+PyDoc_STRVAR(Variant_tp_doc,
+"Variant(object[, signature=Signature(...)])\n"
+"\n"
+"A container for D-Bus types. This is an immutable 'value object' like str\n"
+"and int.\n"
+"\n"
+"The signature may be omitted or None, in which case it will be guessed \n"
+"at construction time from the wrapped object, with the same algorithm\n"
+"used when objects are appended to a message.\n"
+"\n"
+"A Variant v supports the following operations:\n"
+"\n"
+"* v(), v.object (the contained object)\n\n"
+"* v.signature (the signature as a dbus.Signature)\n\n"
+"* v == w if and only if v, w are Variants with the same signature and\n"
+" the objects they contain compare equal\n\n"
+"* bool(v) == bool(v.object)\n"
+"* str(v) == str(v.object)\n\n"
+"* repr(v) returns something like \"Variant(123, signature='i')\"\n\n"
+"* int(v) == int(v.object), if supported; ditto long(v), float(v),\n"
+" hex(v), oct(v)\n\n"
+"* iter(v) iterates over the contained object, if it's iterable\n\n"
+);
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *object;
+ PyObject *signature;
+} Variant;
+
+static struct PyMemberDef Variant_tp_members[] = {
+ {"object", T_OBJECT, offsetof(Variant, object), READONLY,
+ "The wrapped object"},
+ {"signature", T_OBJECT, offsetof(Variant, signature), READONLY,
+ "The D-Bus signature of the contained object (a Signature instance)"},
+ {NULL},
+};
+
+static void
+Variant_tp_dealloc (Variant *self)
+{
+ Py_XDECREF(self->object);
+ self->object = NULL;
+ Py_XDECREF(self->signature);
+ self->signature = NULL;
+ (self->ob_type->tp_free)(self);
+}
+
+/* forward declaration */
+static PyObject *Message_guess_signature(PyObject *unused, PyObject *args);
+
+static PyObject *
+Variant_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ Variant *self;
+ PyObject *obj;
+ PyObject *signature = NULL;
+ static char *argnames[] = {"object", "signature", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:__new__", argnames,
+ &obj, &signature)) {
+ return NULL;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature, somehow... */
+ if (!signature || signature == Py_None) {
+ /* There's no signature, we'll have to guess what the user wanted */
+ PyObject *tuple = Py_BuildValue("(O)", obj);
+
+ if (!tuple) return NULL;
+ signature = Message_guess_signature(NULL, tuple);
+ Py_DECREF(tuple);
+ if (!signature) return NULL;
+ }
+ else if (PyObject_IsInstance(signature, (PyObject *)&SignatureType)) {
+ /* Already a Signature, so that's easy */
+ Py_INCREF(signature);
+ }
+ else {
+ /* See what the Signature constructor thinks of it */
+ signature = PyObject_CallFunction((PyObject *)&SignatureType, "(O)",
+ signature);
+ if (!signature) return NULL;
+ }
+
+ self = (Variant *)(cls->tp_alloc)(cls, 0);
+ if (!self) {
+ Py_DECREF(signature);
+ return NULL;
+ }
+
+ self->signature = signature;
+ Py_INCREF (obj);
+ self->object = obj;
+ return (PyObject *)self;
+}
+
+static PyObject *
+Variant_tp_repr (Variant *self)
+{
+ PyObject *my_repr = NULL;
+ PyObject *obj_repr;
+ PyObject *sig_repr;
+
+ if (!self->object) {
+ return PyString_FromString("<invalid dbus.Variant with no object>");
+ }
+
+ obj_repr = PyObject_Repr(self->object);
+ sig_repr = PyObject_Repr(self->signature);
+ if (obj_repr && sig_repr) {
+ my_repr = PyString_FromFormat("%s(%s, signature=%s)",
+ self->ob_type->tp_name,
+ PyString_AS_STRING(obj_repr),
+ PyString_AS_STRING(sig_repr));
+ }
+ /* whether my_repr is NULL or not: */
+ Py_XDECREF(obj_repr);
+ Py_XDECREF(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Variant_tp_iter(Variant *self)
+{
+ return PyObject_GetIter(self->object);
+}
+
+static PyObject *
+Variant_tp_call(Variant *self, PyObject *args, PyObject *kwargs)
+{
+ if ((args && PyObject_Size(args)) || (kwargs && PyObject_Size(kwargs))) {
+ PyErr_SetString(PyExc_TypeError, "Variant.__call__ takes no arguments");
+ return NULL;
+ }
+ Py_INCREF(self->object);
+ return self->object;
+}
+
+static long
+Variant_tp_hash(Variant *self)
+{
+ return PyObject_Hash(self->object);
+}
+
+static PyObject *
+Variant_tp_richcompare(Variant *self, PyObject *other, int opid)
+{
+ PyObject *ret;
+
+ if (opid == Py_EQ || opid == Py_NE) {
+ if (Variant_Check(other)) {
+ Variant *vo = (Variant *)other;
+ ret = PyObject_RichCompare(self->signature, vo->signature, opid);
+ if (!ret) return NULL;
+ if (!PyObject_IsTrue(ret)) {
+ if (opid == Py_EQ) {
+ /* Signatures are unequal, we require equal. Fail. */
+ return ret;
+ }
+ }
+ else {
+ if (opid == Py_NE) {
+ /* Signatures are unequal, succeed. */
+ return ret;
+ }
+ }
+ Py_DECREF(ret);
+ ret = PyObject_RichCompare(self->object, vo->object, opid);
+ if (!ret) return NULL;
+ if (!PyObject_IsTrue(ret)) {
+ if (opid == Py_EQ) {
+ /* Objects are unequal, we require equal. Fail. */
+ return ret;
+ }
+ }
+ else {
+ if (opid == Py_NE) {
+ /* Objects are unequal, succeed. */
+ return ret;
+ }
+ }
+ Py_DECREF(ret);
+ if (opid == Py_NE) {
+ Py_RETURN_FALSE;
+ }
+ else {
+ Py_RETURN_TRUE;
+ }
+ }
+ /* Types are dissimilar */
+ if (opid == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "Variant objects do not support "
+ "ordered comparison (<, >, <=, >=)");
+ return NULL;
+ }
+}
+
+static PyObject *
+Variant_tp_str(Variant *self)
+{
+ if (PyString_Check(self->object)) {
+ Py_INCREF(self->object);
+ return self->object;
+ }
+ return PyObject_Str(self->object);
+}
+
+static int
+Variant_tp_nonzero(Variant *self)
+{
+ return PyObject_IsTrue(self->object);
+}
+
+static PyObject *
+Variant_nb_int(Variant *self)
+{
+ if (PyInt_Check(self->object) || PyLong_Check(self->object)) {
+ Py_INCREF(self->object);
+ return self->object;
+ }
+ return PyNumber_Int(self->object);
+}
+
+static PyObject *
+Variant_nb_oct(Variant *self)
+{
+ PyObject *ret;
+ PyObject *i = Variant_nb_int(self);
+
+ if (!i) return NULL;
+ if (!PyNumber_Check(i) || !i->ob_type->tp_as_number->nb_oct) {
+ PyErr_SetString(PyExc_TypeError, "Value stored in Variant does not "
+ "support conversion to octal");
+ Py_DECREF(i);
+ return NULL;
+ }
+ ret = (i->ob_type->tp_as_number->nb_oct)(i);
+ Py_DECREF(i);
+ return ret;
+}
+
+static PyObject *
+Variant_nb_hex(Variant *self)
+{
+ PyObject *ret;
+ PyObject *i = Variant_nb_int(self);
+
+ if (!i) return NULL;
+ if (!PyNumber_Check(i) || !i->ob_type->tp_as_number->nb_hex) {
+ PyErr_SetString(PyExc_TypeError, "Value stored in Variant does not "
+ "support conversion to hexadecimal");
+ Py_DECREF(i);
+ return NULL;
+ }
+ ret = (i->ob_type->tp_as_number->nb_hex)(i);
+ Py_DECREF(i);
+ return ret;
+}
+
+static PyObject *
+Variant_nb_long(Variant *self)
+{
+ if (PyLong_Check(self->object)) {
+ Py_INCREF(self->object);
+ return self->object;
+ }
+ return PyNumber_Long(self->object);
+}
+
+static PyObject *
+Variant_nb_float(Variant *self)
+{
+ if (PyFloat_Check(self->object)) {
+ Py_INCREF(self->object);
+ return self->object;
+ }
+ return PyNumber_Float(self->object);
+}
+
+static PyNumberMethods Variant_tp_as_number = {
+ NULL, /* nb_add */
+ NULL, /* nb_subtract */
+ NULL, /* nb_multiply */
+ NULL, /* nb_divide */
+ NULL, /* nb_remainder */
+ NULL, /* nb_divmod */
+ NULL, /* nb_power */
+ NULL, /* nb_negative */
+ NULL, /* tp_positive */
+ NULL, /* tp_absolute */
+ (inquiry)Variant_tp_nonzero, /* tp_nonzero */
+ NULL, /* nb_invert */
+ NULL, /* nb_lshift */
+ NULL, /* nb_rshift */
+ NULL, /* nb_and */
+ NULL, /* nb_xor */
+ NULL, /* nb_or */
+ NULL, /* nb_coerce */
+ (unaryfunc)Variant_nb_int,
+ (unaryfunc)Variant_nb_long,
+ (unaryfunc)Variant_nb_float,
+ (unaryfunc)Variant_nb_oct,
+ (unaryfunc)Variant_nb_hex,
+ NULL, /* nb_inplace_add */
+ NULL, /* nb_inplace_subtract */
+ NULL, /* nb_inplace_multiply */
+ NULL, /* nb_inplace_divide */
+ NULL, /* nb_inplace_remainder */
+ NULL, /* nb_inplace_power */
+ NULL, /* nb_inplace_lshift */
+ NULL, /* nb_inplace_rshift */
+ NULL, /* nb_inplace_and */
+ NULL, /* nb_inplace_xor */
+ NULL, /* nb_inplace_or */
+ NULL, /* nb_floor_divide */
+ NULL, /* nb_true_divide */
+ NULL, /* nb_inplace_floor_divide */
+ NULL, /* nb_inplace_true_divide */
+};
+
+static PyTypeObject VariantType = {
+ PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+ 0,
+ "dbus.Variant",
+ sizeof(Variant),
+ 0,
+ (destructor)Variant_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Variant_tp_repr, /* tp_repr */
+ &Variant_tp_as_number, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)Variant_tp_hash, /* tp_hash */
+ (ternaryfunc)Variant_tp_call, /* tp_call */
+ (reprfunc)Variant_tp_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Variant_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)Variant_tp_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)Variant_tp_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ Variant_tp_members, /* 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 */
+ Variant_tp_new, /* tp_new */
+};
+
+static inline int
+init_container_types(void)
+{
+ ArrayType.tp_base = &PyList_Type;
+ if (PyType_Ready(&ArrayType) < 0) return 0;
+ ArrayType.tp_print = NULL;
+
+ DictType.tp_base = &PyDict_Type;
+ if (PyType_Ready(&DictType) < 0) return 0;
+ DictType.tp_print = NULL;
+
+ if (PyType_Ready(&VariantType) < 0) return 0;
+
+ return 1;
+}
+
+static inline int
+insert_container_types(PyObject *this_module)
+{
+ Py_INCREF(&ArrayType);
+ if (PyModule_AddObject(this_module, "Array",
+ (PyObject *)&ArrayType) < 0) return 0;
+
+ Py_INCREF(&DictType);
+ if (PyModule_AddObject(this_module, "Dictionary",
+ (PyObject *)&DictType) < 0) return 0;
+
+ Py_INCREF(&VariantType);
+ if (PyModule_AddObject(this_module, "Variant",
+ (PyObject *)&VariantType) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
+
diff --git a/_dbus_bindings/dbus_bindings.py b/_dbus_bindings/dbus_bindings.py
new file mode 100644
index 0000000..cd4139a
--- /dev/null
+++ b/_dbus_bindings/dbus_bindings.py
@@ -0,0 +1,27 @@
+# Backwards-compatibility with the old dbus_bindings.
+
+# Exceptions
+from _dbus_bindings import DBusException
+class ConnectionError(Exception): pass
+
+# Types
+from _dbus_bindings import Int16, UInt16, Int32, UInt32, Int64, UInt64,\
+ Variant, ObjectPath, Signature, Byte, ByteArray
+# Don't bother importing SignatureIter, it can't be instantiated
+# These used to be specialized subclasses, but these are unambiguous
+String = unicode
+Boolean = bool
+Array = list # FIXME: c'tor params
+Double = float
+Struct = tuple
+Dictionary = dict # FIXME: c'tor params
+
+# Messages
+from _dbus_bindings import Message, SignalMessage as Signal,\
+ MethodCallMessage as MethodCall,\
+ MethodReturnMessage as MethodReturn,\
+ ErrorMessage as Error
+# MessageIter has gone away, thankfully
+
+# Connection
+from _dbus_bindings import Connection
diff --git a/_dbus_bindings/debug-impl.h b/_dbus_bindings/debug-impl.h
new file mode 100644
index 0000000..ae87794
--- /dev/null
+++ b/_dbus_bindings/debug-impl.h
@@ -0,0 +1,49 @@
+/* Debug code for _dbus_bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#if 0
+# include <sys/types.h>
+# include <unistd.h>
+
+# define USING_DBG
+# define DBG(format, ...) fprintf(stderr, "DEBUG: " format "\n",\
+ __VA_ARGS__)
+static void _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 */
+}
+# define DBG_EXC(format, ...) do {DBG(format, __VA_ARGS__); \
+ _dbg_exc();} while (0)
+#else
+# undef USING_DBG
+# define DBG(format, ...) do {} while (0)
+# define DBG_EXC(format, ...) do {} while (0)
+#endif
diff --git a/_dbus_bindings/exceptions-impl.h b/_dbus_bindings/exceptions-impl.h
new file mode 100644
index 0000000..6ba0c19
--- /dev/null
+++ b/_dbus_bindings/exceptions-impl.h
@@ -0,0 +1,71 @@
+/* D-Bus exception base classes.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+static PyObject *DBusException;
+
+PyDoc_STRVAR(DBusException__doc__, "Represents any D-Bus-related error.");
+
+static inline PyObject *
+DBusException_ConsumeError (DBusError *error)
+{
+ PyErr_Format (DBusException, "%s: %s", error->name, error->message);
+ dbus_error_free(error);
+ return NULL;
+}
+
+static inline PyObject *
+DBusException_UnusableMessage (void)
+{
+ PyErr_SetString (DBusException,
+ "Message object is uninitialized, or has become unusable "
+ "due to error while appending arguments");
+ return NULL;
+}
+
+static inline int
+init_exception_types (void)
+{
+ PyObject *docstring;
+
+ /* We call it dbus.DBusException because that's where you should import it
+ from. */
+ DBusException = PyErr_NewException("dbus.DBusException", NULL, NULL);
+ if (!DBusException) return 0;
+ docstring = PyString_FromString(DBusException__doc__);
+ if (!docstring) return 0;
+ if (PyObject_SetAttrString (DBusException, "__doc__", docstring)) return 0;
+ Py_DECREF (docstring);
+ return 1;
+}
+
+static inline int
+insert_exception_types (PyObject *this_module)
+{
+ if (PyModule_AddObject(this_module, "DBusException", DBusException) < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/generic-impl.h b/_dbus_bindings/generic-impl.h
new file mode 100644
index 0000000..71fbafe
--- /dev/null
+++ b/_dbus_bindings/generic-impl.h
@@ -0,0 +1,108 @@
+/* General Python glue code, used in _dbus_bindings but not actually anything
+ * to do with D-Bus.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define DEFERRED_ADDRESS(ADDR) 0
+
+static PyObject *empty_tuple = NULL;
+
+/* A generic repr() implementation for int subclasses, returning something
+ * like 'dbus.Int16(123)'.
+ * Equivalent to the following Python:
+ * def __repr__(self):
+ * return '%s(%r)' % (self.__class__, int.__repr__(self))
+ */
+static PyObject *
+int_subclass_tp_repr (PyObject *self)
+{
+ PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
+ PyObject *my_repr;
+
+ if (!parent_repr) return NULL;
+ my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
+ PyString_AS_STRING(parent_repr));
+ /* whether my_repr is NULL or not: */
+ Py_DECREF(parent_repr);
+ return my_repr;
+}
+
+/* A generic repr() implementation for long subclasses, returning something
+ * like 'dbus.Int64(123L)'.
+ * Equivalent to the following Python:
+ * def __repr__(self):
+ * return '%s(%r)' % (self.__class__, long.__repr__(self))
+ */
+static PyObject *
+long_subclass_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
+ PyObject *my_repr;
+
+ if (!parent_repr) return NULL;
+ my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
+ PyString_AS_STRING(parent_repr));
+ /* whether my_repr is NULL or not: */
+ Py_DECREF(parent_repr);
+ return my_repr;
+}
+
+/* A generic repr() implementation for str subclasses, returning something
+ * like "dbus.ObjectPath('/foo/bar')".
+ * Equivalent to the following Python:
+ * def __repr__(self):
+ * return '%s(%r)' % (self.__class__, str.__repr__(self))
+ */
+static PyObject *
+str_subclass_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyString_Type.tp_repr)(self);
+ PyObject *my_repr;
+
+ if (!parent_repr) return NULL;
+ my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
+ PyString_AS_STRING(parent_repr));
+ /* whether my_repr is NULL or not: */
+ Py_DECREF(parent_repr);
+ return my_repr;
+}
+
+/* Take the global interpreter lock and decrement the reference count.
+ * Suitable for calling from a C callback. */
+static void
+Glue_TakeGILAndXDecref(PyObject *obj)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ Py_XDECREF(obj);
+ PyGILState_Release(gil);
+}
+
+static inline int
+init_generic(void)
+{
+ empty_tuple = PyTuple_New(0);
+ if (!empty_tuple) return 0;
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/message-append-impl.h b/_dbus_bindings/message-append-impl.h
new file mode 100644
index 0000000..99b8dea
--- /dev/null
+++ b/_dbus_bindings/message-append-impl.h
@@ -0,0 +1,863 @@
+/* D-Bus Message serialization. This contains all the logic to map from
+ * Python objects to D-Bus types.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(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"
+"variant Variant\n"
+" any object (guess type as below)\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"
+"------------------------------- ---------------------------\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"
+);
+
+PyDoc_STRVAR(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"
+"bool boolean (y)\n"
+"dbus.Int16, etc. the corresponding type\n"
+"any other int subclass int32 (i) (FIXME: make this error?)\n"
+"long or a subclass int64 (x) (FIXME: make this error?)\n"
+"float or a subclass double (d)\n"
+"dbus.ObjectPath, dbus.Signature the corresponding type (o, g)\n"
+"dbus.ByteArray or subclass array of byte (ay)\n"
+"dbus.Byte or subclass byte (y)\n"
+"str or any other subclass string (s)\n"
+"unicode or a subclass string (s)\n"
+"dbus.Variant or subclass variant (v), guess contents' type\n"
+"tuple or a subclass struct ((...)), guess contents' types\n"
+"list or a subclass array (a...), guess contents' type\n"
+" according to type of first item\n"
+"dict or a subclass dict (a{...}), guess key, value type\n"
+" according to types for an arbitrary item\n"
+"anything else raise TypeError\n"
+"------------------------------- ---------------------------\n"
+);
+
+/* Return a new reference. */
+static PyObject *
+_signature_string_from_pyobject(PyObject *obj)
+{
+ /* Ordering is important: some of these are subclasses of each other. */
+ if (obj == Py_True || obj == Py_False)
+ return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
+ else if (PyInt_Check(obj)) {
+ if (Int16_Check(obj))
+ return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
+ else if (Int32_Check(obj))
+ return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
+ else if (UInt16_Check(obj))
+ return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
+ else
+ return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
+ }
+ else if (PyLong_Check(obj)) {
+ if (Int64_Check(obj))
+ return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
+ else if (UInt32_Check (obj))
+ return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
+ else if (UInt64_Check (obj))
+ return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
+ else
+ return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
+ }
+ else if (PyUnicode_Check(obj))
+ return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
+ else if (PyFloat_Check(obj))
+ return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
+ else if (Variant_Check(obj)) {
+ return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
+ }
+ else if (PyString_Check(obj)) {
+ if (Byte_Check(obj))
+ return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
+ else if (ObjectPath_Check(obj))
+ return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
+ else if (Signature_Check(obj))
+ return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
+ else if (ByteArray_Check(obj))
+ return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING);
+ else
+ return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
+ }
+ else if (PyTuple_Check (obj)) {
+ int 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;
+ int i;
+
+ if (!list) return NULL;
+ if (len == 0) {
+ PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
+ Py_DECREF (list);
+ return NULL;
+ }
+ /* Set the first and last elements of list to be the parentheses */
+ item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
+ if (PyList_SetItem(list, 0, item) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
+ if (PyList_SetItem(list, len + 1, item) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ if (!item || !PyList_GET_ITEM(list, 0)) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ item = NULL;
+
+ for (i = 0; i < len; i++) {
+ item = PyTuple_GetItem(obj, i);
+ if (!item) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ item = _signature_string_from_pyobject(item);
+ if (!item) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ if (PyList_SetItem(list, i + 1, item) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ item = NULL;
+ }
+ empty_str = PyString_FromString("");
+ if (!empty_str) {
+ /* really shouldn't happen */
+ Py_DECREF(list);
+ return NULL;
+ }
+ ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
+ /* whether ret is NULL or not, */
+ Py_DECREF(empty_str);
+ Py_DECREF(list);
+ return ret;
+ }
+ else if (PyList_Check(obj)) {
+ PyObject *tmp;
+ PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
+ if (!ret) return NULL;
+ 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);
+ if (!tmp) return NULL;
+ PyString_ConcatAndDel (&ret, tmp);
+ return ret;
+ }
+ else if (PyDict_Check(obj)) {
+ PyObject *key, *value, *keysig, *valuesig;
+ int pos = 0;
+ PyObject *ret = NULL;
+
+ 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);
+ valuesig = _signature_string_from_pyobject(value);
+ if (keysig && valuesig) {
+ ret = PyString_FromFormat ((DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ "%s%s"
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
+ PyString_AS_STRING(keysig),
+ PyString_AS_STRING(valuesig));
+ }
+ Py_XDECREF(keysig);
+ Py_XDECREF(valuesig);
+ return ret;
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
+ "to use to encode type \"%s\"",
+ obj->ob_type->tp_name);
+ return NULL;
+ }
+}
+
+static PyObject *
+Message_guess_signature(PyObject *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 *)&SignatureType, "(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);
+ if (!tmp) {
+ DBG("%s", "Message_guess_signature: failed");
+ return NULL;
+ }
+ if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
+ PyErr_SetString(PyExc_RuntimeError, "Internal error: "
+ "_signature_string_from_pyobject returned "
+ "a bad result");
+ Py_DECREF(tmp);
+ return NULL;
+ }
+ ret = PyObject_CallFunction((PyObject *)&SignatureType, "(s#)",
+ PyString_AS_STRING (tmp) + 1,
+ PyString_GET_SIZE (tmp) - 2);
+ DBG("Message_guess_signature: returning Signature at %p", ret);
+ Py_DECREF (tmp);
+ return ret;
+}
+
+static int _message_iter_append_pyobject(DBusMessageIter *appender,
+ DBusSignatureIter *sig_iter,
+ PyObject *obj);
+
+static int
+_message_iter_append_string(DBusMessageIter *appender,
+ int sig_type, PyObject *obj)
+{
+ char *s;
+
+ if (PyString_Check (obj)) {
+ /* Raise TypeError if the string has embedded NULs */
+ if (PyString_AsStringAndSize (obj, &s, NULL) < 0) return -1;
+ /* Surely there's a faster stdlib way to validate UTF-8... */
+ PyObject *unicode = PyUnicode_DecodeUTF8 (s, PyString_GET_SIZE (obj),
+ NULL);
+ if (!unicode) {
+ PyErr_SetString (PyExc_UnicodeError, "String parameters "
+ "to be sent over D-Bus must be valid UTF-8");
+ return -1;
+ }
+ Py_DECREF (unicode);
+ unicode = NULL;
+
+ DBG("Performing actual append: string %s", s);
+ if (!dbus_message_iter_append_basic (appender, sig_type,
+ &s)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ }
+ else if (PyUnicode_Check (obj)) {
+ PyObject *utf8 = PyUnicode_AsUTF8String (obj);
+ if (!utf8) return -1;
+ /* Raise TypeError if the string has embedded NULs */
+ if (PyString_AsStringAndSize (utf8, &s, NULL) < 0) return -1;
+ DBG("Performing actual append: string (from unicode) %s", s);
+ if (!dbus_message_iter_append_basic (appender, sig_type, &s)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ Py_DECREF (utf8);
+ }
+ else {
+ PyErr_SetString (PyExc_TypeError,
+ "Expected a string or unicode object");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
+{
+ unsigned char y;
+
+ if (PyString_Check(obj)) {
+ if (PyString_GET_SIZE(obj) != 1) {
+ PyErr_Format(PyExc_ValueError, "Expected a string of "
+ "length 1 byte, but found %d bytes",
+ PyString_GET_SIZE (obj));
+ return -1;
+ }
+ y = *(unsigned char *)PyString_AS_STRING(obj);
+ }
+ else {
+ long i = PyInt_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 (from unicode) \\x%02x", (unsigned)y);
+ if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+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);
+
+ 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);
+ if (ret == 0) {
+ ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value);
+ }
+ DBG("%s", "Closing DICT_ENTRY container");
+ if (!dbus_message_iter_close_container(appender, &sub)) {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+out:
+ Py_DECREF(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;
+
+#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
+
+ 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;
+ 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
+ }
+
+ if (mode == DBUS_TYPE_DICT_ENTRY) {
+ ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
+ obj, contents);
+ }
+ else {
+ ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
+ contents);
+ }
+ Py_DECREF(contents);
+ if (ret < 0) {
+ break;
+ }
+ }
+ if (PyErr_Occurred()) ret = -1;
+ /* This must be run as cleanup, even on failure. */
+ DBG("Closing %c container", container);
+ if (!dbus_message_iter_close_container(appender, &sub_appender)) {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+
+out:
+ Py_XDECREF(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 */
+ int len = PyString_GET_SIZE(obj);
+ const char *s;
+ DBusMessageIter sub;
+ int ret;
+
+ s = PyString_AS_STRING(obj);
+ DBG("Opening ARRAY container", 0);
+ 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", len);
+ if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
+ ret = 0;
+ }
+ else {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+ DBG("Clossing ARRAY container", 0);
+ 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)
+{
+ DBusMessageIter sub;
+ DBusSignatureIter sig_iter;
+ const char *sig_str;
+ PyObject *sig, *guess_args;
+ int ret;
+
+ if (Variant_Check (obj)) {
+ /* make sig an owned reference */
+ sig = ((Variant *)obj)->signature;
+ if (!sig) {
+ PyErr_SetString(PyExc_RuntimeError, "Internal error: "
+ "broken Variant");
+ return -1;
+ }
+ Py_INCREF(sig);
+ /* obj is still a borrowed reference though */
+ obj = ((Variant *)obj)->object;
+ }
+ else {
+ /* Either it's a Variant with no explicit signature, or it's a
+ value. */
+ guess_args = Py_BuildValue("(O)", obj);
+ if (!guess_args) return -1;
+ sig = Message_guess_signature (NULL, guess_args);
+ Py_DECREF(guess_args);
+ if (!sig) return -1;
+ }
+
+ sig_str = PyString_AsString(sig);
+ if (!sig_str) return -1;
+
+ dbus_signature_iter_init (&sig_iter, sig_str);
+
+ DBG("Opening VARIANT container", 0);
+ if (!dbus_message_iter_open_container (appender, DBUS_TYPE_VARIANT,
+ sig_str, &sub)) {
+ PyErr_NoMemory();
+ ret = -1;
+ goto out;
+ }
+ ret = _message_iter_append_pyobject(&sub, &sig_iter, obj);
+ DBG("Closing VARIANT container", 0);
+ if (!dbus_message_iter_close_container (appender, &sub)) {
+ PyErr_NoMemory();
+ ret = -1;
+ }
+out:
+ Py_XDECREF (sig);
+ return ret;
+}
+
+static int
+_message_iter_append_pyobject(DBusMessageIter *appender,
+ DBusSignatureIter *sig_iter,
+ PyObject *obj)
+{
+ int sig_type = dbus_signature_iter_get_current_type (sig_iter);
+ union {
+ dbus_bool_t b;
+ double d;
+ dbus_uint16_t uint16;
+ dbus_int16_t int16;
+ dbus_uint32_t uint32;
+ dbus_int32_t int32;
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ dbus_uint64_t uint64;
+ dbus_int64_t int64;
+#endif
+ } u;
+ int ret = -1;
+
+#ifdef USING_DBG
+ fprintf(stderr, "Appending object: ");
+ PyObject_Print(obj, stderr, 0);
+ fprintf(stderr, ", dbus wants type %c\n", 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.b = 1;
+ }
+ else {
+ u.b = 0;
+ }
+ DBG("Performing actual append: bool(%ld)", (long)u.b);
+ if (!dbus_message_iter_append_basic (appender, sig_type, &u.b)) {
+ PyErr_NoMemory();
+ ret = -1;
+ break;
+ }
+ ret = 0;
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ u.d = PyFloat_AsDouble (obj);
+ if (PyErr_Occurred()) {
+ ret = -1;
+ break;
+ }
+ DBG("Performing actual append: double(%f)", u.d);
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
+ PyErr_NoMemory();
+ ret = -1;
+ break;
+ }
+ ret = 0;
+ break;
+
+ /* The integer types are all basically the same - we delegate to
+ intNN_range_check() */
+#define PROCESS_INTEGER(size) \
+ u.size = size##_range_check (obj);\
+ if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
+ ret = -1; \
+ break; \
+ }\
+ DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
+ if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
+ PyErr_NoMemory();\
+ ret = -1;\
+ break;\
+ } \
+ ret = 0;
+
+ case DBUS_TYPE_INT16:
+ PROCESS_INTEGER(int16)
+ break;
+ case DBUS_TYPE_UINT16:
+ PROCESS_INTEGER(uint16)
+ break;
+ case DBUS_TYPE_INT32:
+ PROCESS_INTEGER(int32)
+ break;
+ case DBUS_TYPE_UINT32:
+ PROCESS_INTEGER(uint32)
+ break;
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ case DBUS_TYPE_INT64:
+ PROCESS_INTEGER(int64)
+ break;
+ case DBUS_TYPE_UINT64:
+ PROCESS_INTEGER(uint64)
+ break;
+#else
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ PyErr_SetString (PyExc_RuntimeError, "64-bit integers 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);
+ 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 && PyString_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;
+
+ 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);
+#ifdef USING_DBG
+ { dbus_bool_t b =
+#endif
+ dbus_signature_iter_next(sig_iter);
+#ifdef USING_DBG
+ DBG("- result: %ld", (long)b);
+ }
+#endif
+ return 0;
+}
+
+
+static PyObject *
+Message_append(Message *self, PyObject *args, PyObject *kwargs)
+{
+ const char *signature = NULL;
+ PyObject *signature_obj = NULL;
+ DBusSignatureIter sig_iter;
+ DBusMessageIter appender;
+ int i;
+ static char *argnames[] = {"signature", NULL};
+
+ if (!self->msg) return DBusException_UnusableMessage ();
+
+#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(empty_tuple, kwargs, "|z:append",
+ argnames, &signature)) return NULL;
+
+ if (!signature) {
+ DBG("%s", "No signature for message, guessing...");
+ signature_obj = Message_guess_signature(NULL, args);
+ if (!signature_obj) return NULL;
+ signature = PyString_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_signature_iter_init(&sig_iter, signature);
+ dbus_message_iter_init_append(self->msg, &appender);
+ for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
+ if (_message_iter_append_pyobject(&appender, &sig_iter,
+ PyTuple_GET_ITEM (args, i)) < 0) {
+ goto hosed;
+ }
+ }
+ if (dbus_signature_iter_get_current_type(&sig_iter)
+ != DBUS_TYPE_INVALID) {
+ PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
+ "signature than in Python arguments");
+ goto hosed;
+ }
+
+ /* success! */
+ Py_XDECREF(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_XDECREF(signature_obj);
+ return NULL;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/message-get-args-impl.h b/_dbus_bindings/message-get-args-impl.h
new file mode 100644
index 0000000..ccd52ce
--- /dev/null
+++ b/_dbus_bindings/message-get-args-impl.h
@@ -0,0 +1,403 @@
+/* D-Bus Message unserialization. This contains all the logic to map from
+ * D-Bus types to Python objects.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(Message_get_args__doc__,
+"get_args(**kwargs) -> tuple\n\n"
+"Return the message's arguments. Keyword arguments control the translation\n"
+"of D-Bus types to Python:\n"
+"\n"
+":Parameters:\n"
+" `integer_bytes` : bool\n"
+" If true, return D-Bus bytes as Python ints (loses type information).\n"
+" If false (default and recommended), return D-Bus bytes as Byte\n"
+" objects, a subclass of str with length always 1.\n"
+" `byte_arrays` : bool\n"
+" If true, convert arrays of byte (signature 'ay') into ByteArray,\n"
+" a str subclass whose subscript operator returns Byte objects.\n"
+" If false (default), convert them like any other array (into a\n"
+" list of Bytes, or a list of ints if integer_bytes is true)."
+" `untyped_integers` : bool\n"
+" If true, fold all intNN, uintNN types into Python int or long (loses\n"
+" type information).\n"
+" If false (default), convert them into the appropriate subclasses.\n"
+" `variant_unpack_level` : int\n"
+" If >1, unpack e.g. a variant containing a variant containing a\n"
+" string as if it was a string (loses type information).\n"
+" If 1, unpack it as a Variant containing a string (i.e. remove\n"
+" exactly one level of \"variantness\".\n"
+" If 0 (default), unpack it as a Variant containing a Variant\n"
+" containing a string, to avoid ambiguity completely.\n"
+" `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"
+"\n"
+"Most of the type mappings should be fairly obvious:\n"
+"\n"
+"--------------- ------------\n"
+"D-Bus Python\n"
+"=============== ============\n"
+"byte (y) Byte (int if integer_bytes set)\n"
+"bool (b) bool\n"
+"Signature (g) Signature (str subclass)\n"
+"intNN, uintNN IntNN, UIntNN (int/long subclass)\n"
+" (int/long if untyped_integers set)\n"
+"double (d) float\n"
+"string (s) unicode (str if utf8_strings set)\n"
+"Object path (o) ObjectPath (str subclass)\n"
+"dict (a{...}) dict\n"
+"array (a...) list of appropriate types\n"
+"byte array (ay) ByteArray (str subclass) if byte_arrays set; or\n"
+" list of int, if integer_bytes set; or\n"
+" list of Byte\n"
+"variant (v) Variant containing appropriate type\n"
+"struct ((...)) tuple of appropriate types\n"
+"--------------- ------------\n"
+);
+
+typedef struct {
+ int integer_bytes;
+ int byte_arrays;
+ int untyped_integers;
+ int variant_unpack_level;
+ int utf8_strings;
+} Message_get_args_options;
+
+static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts,
+ int top_level);
+
+/* 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 top_level)
+{
+ 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, top_level);
+ 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 (Byte is %p)\n", item->ob_type,
+ &ByteType);
+#endif
+ ret = PyList_Append(list, item);
+ Py_DECREF(item);
+ item = NULL;
+ 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;
+}
+
+/* Returns a new reference. */
+static PyObject *
+_message_iter_get_pyobject(DBusMessageIter *iter,
+ Message_get_args_options *opts, int top_level)
+{
+ union {
+ const char *s;
+ unsigned char y;
+ dbus_bool_t b;
+ double d;
+ dbus_uint16_t u16;
+ dbus_int16_t i16;
+ dbus_uint32_t u32;
+ dbus_int32_t i32;
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+ dbus_uint64_t u64;
+ dbus_int64_t i64;
+#endif
+ } u;
+
+ int type = dbus_message_iter_get_arg_type(iter);
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ DBG("%s", "found a string");
+ dbus_message_iter_get_basic(iter, &u.s);
+ if (opts->utf8_strings)
+ return PyString_FromString(u.s);
+ else
+ return PyUnicode_DecodeUTF8(u.s, strlen(u.s), NULL);
+
+ case DBUS_TYPE_SIGNATURE:
+ DBG("%s", "found a signature");
+ dbus_message_iter_get_basic(iter, &u.s);
+ return PyObject_CallFunction((PyObject *)&SignatureType, "(s)", u.s);
+
+ case DBUS_TYPE_OBJECT_PATH:
+ DBG("%s", "found an object path");
+ dbus_message_iter_get_basic(iter, &u.s);
+ return PyObject_CallFunction((PyObject *)&ObjectPathType, "(s)", u.s);
+
+ case DBUS_TYPE_DOUBLE:
+ DBG("%s", "found a double");
+ dbus_message_iter_get_basic(iter, &u.d);
+ return PyFloat_FromDouble(u.d);
+
+ case DBUS_TYPE_INT16:
+ DBG("%s", "found an int16");
+ dbus_message_iter_get_basic(iter, &u.i16);
+ if (opts->untyped_integers)
+ return PyInt_FromLong(u.i16);
+ else
+ return PyObject_CallFunction((PyObject *)&Int16Type, "(i)", (int)u.i16);
+
+ case DBUS_TYPE_UINT16:
+ DBG("%s", "found a uint16");
+ dbus_message_iter_get_basic(iter, &u.u16);
+ if (opts->untyped_integers)
+ return PyInt_FromLong(u.u16);
+ else
+ return PyObject_CallFunction((PyObject *)&UInt16Type, "(i)", (int)u.u16);
+
+ case DBUS_TYPE_INT32:
+ DBG("%s", "found an int32");
+ dbus_message_iter_get_basic(iter, &u.i32);
+ if (opts->untyped_integers)
+ return PyInt_FromLong(u.i32);
+ else
+ return PyObject_CallFunction((PyObject *)&Int32Type, "(l)", (long)u.i32);
+
+ case DBUS_TYPE_UINT32:
+ DBG("%s", "found a uint32");
+ dbus_message_iter_get_basic(iter, &u.u32);
+ if (opts->untyped_integers)
+ return PyLong_FromUnsignedLong(u.u32);
+ else
+ return PyObject_CallFunction((PyObject *)&UInt32Type, "(k)",
+ (unsigned long)u.u32);
+
+#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);
+ if (opts->untyped_integers)
+ return PyLong_FromLongLong(u.i64);
+ else
+ return PyObject_CallFunction((PyObject *)&Int64Type, "(L)",
+ (long long)u.i64);
+
+ case DBUS_TYPE_UINT64:
+ DBG("%s", "found a uint64");
+ dbus_message_iter_get_basic(iter, &u.u64);
+ if (opts->untyped_integers)
+ return PyLong_FromUnsignedLongLong(u.u64);
+ else
+ return PyObject_CallFunction((PyObject *)&UInt64Type, "(K)",
+ (unsigned long long)u.u64);
+#else
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ PyErr_SetString (PyExc_RuntimeError, "64-bit integers not "
+ "supported on this platform");
+ return NULL;
+#endif
+
+ case DBUS_TYPE_BYTE:
+ DBG("%s", "found a byte");
+ dbus_message_iter_get_basic(iter, &u.y);
+ if (opts->integer_bytes)
+ return PyInt_FromLong(u.y);
+ else
+ return Byte_from_uchar(u.y);
+
+ case DBUS_TYPE_BOOLEAN:
+ DBG("%s", "found a bool");
+ dbus_message_iter_get_basic(iter, &u.b);
+ return PyBool_FromLong(u.b);
+
+ 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) {
+ DBusMessageIter entries, kv;
+ PyObject *key, *value, *dict;
+
+ DBG("%s", "no, actually it's a dict...");
+ dict = PyObject_CallObject((PyObject *)&DictType,
+ empty_tuple);
+ if (!dict) return NULL;
+
+ dbus_message_iter_recurse(iter, &entries);
+ while ((type = dbus_message_iter_get_arg_type(&entries))
+ == DBUS_TYPE_DICT_ENTRY) {
+ DBG("%s", "dict entry...");
+ key = NULL;
+ value = NULL;
+ dbus_message_iter_recurse(&entries, &kv);
+ key = _message_iter_get_pyobject(&kv, opts, 1);
+ if (key) {
+ dbus_message_iter_next(&kv);
+ value = _message_iter_get_pyobject(&kv, opts, 1);
+ if (value && PyDict_SetItem(dict, key, value) == 0) {
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ dbus_message_iter_next(&entries);
+ continue;
+ }
+ }
+ /* error */
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ Py_XDECREF(dict);
+ return NULL;
+ }
+ return dict;
+ }
+ else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
+ int n;
+ DBG("%s", "actually, a byte array...");
+ dbus_message_iter_get_fixed_array(iter,
+ (const unsigned char **)&u.s,
+ &n);
+ return ByteArray_from_uchars((const unsigned char *)u.s, n);
+ }
+ else {
+ DBusMessageIter sub;
+ PyObject *list = PyObject_CallObject((PyObject *)&ArrayType,
+ empty_tuple);
+ DBG("%s", "a normal array...");
+ if (!list) return NULL;
+ dbus_message_iter_recurse(iter, &sub);
+ if (_message_iter_append_all_to_list(&sub, list, opts, 1) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ return list;
+ }
+
+ case DBUS_TYPE_STRUCT:
+ {
+ PyObject *tuple;
+ DBusMessageIter sub;
+ PyObject *list = PyList_New(0);
+ DBG("%s", "found a struct...");
+ if (!list) return NULL;
+ dbus_message_iter_recurse(iter, &sub);
+ if (_message_iter_append_all_to_list (&sub, list, opts, 1) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ tuple = PyList_AsTuple(list);
+ /* whether tuple is NULL or not, we take the same action: */
+ Py_DECREF(list);
+ return tuple;
+ }
+
+ case DBUS_TYPE_VARIANT:
+ {
+ DBusMessageIter sub;
+
+ DBG("%s", "found a variant...");
+ dbus_message_iter_recurse(iter, &sub);
+ if (opts->variant_unpack_level > 1) {
+ /* throw away arbitrarily many layers of Variant wrapper */
+ return _message_iter_get_pyobject(&sub, opts, 1);
+ }
+ else {
+ /* recurse into the object, and this time don't throw away
+ * Variant wrappers */
+ PyObject *object = _message_iter_get_pyobject(&sub, opts, 0);
+ PyObject *ret;
+ if (!object) return NULL;
+ if (top_level && opts->variant_unpack_level == 1) return object;
+ ret = PyObject_CallFunction((PyObject *)&VariantType,
+ "(Os)", object,
+ dbus_message_iter_get_signature (&sub));
+ /* whether ret is NULL or not, we take the same action: */
+ Py_DECREF(object);
+ return ret;
+ }
+ }
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
+ "message", type);
+ return NULL;
+ }
+}
+
+static PyObject *
+Message_get_args(Message *self, PyObject *args, PyObject *kwargs)
+{
+ Message_get_args_options opts = { 0, 0, 0, 0, 0 };
+ static char *argnames[] = { "integer_bytes", "byte_arrays",
+ "untyped_integers",
+ "variant_unpack_level",
+ "utf8_strings", NULL };
+ PyObject *list, *tuple = NULL;
+ DBusMessageIter iter;
+
+ if (PyTuple_Size(args) != 0) {
+ PyErr_SetString(PyExc_TypeError, "get_args takes no positional "
+ "arguments");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iiiii:get_args", argnames,
+ &(opts.integer_bytes), &(opts.byte_arrays),
+ &(opts.untyped_integers),
+ &(opts.variant_unpack_level),
+ &(opts.utf8_strings))) return NULL;
+ if (!self->msg) return DBusException_UnusableMessage();
+
+ 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, 1) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ }
+
+#ifdef USING_DBG
+ fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
+ PyObject_Print(list, stderr, 0);
+ fprintf(stderr, "\n");
+#endif
+
+ tuple = PyList_AsTuple(list);
+ /* whether tuple is NULL or not, we take the same action: */
+ Py_DECREF(list);
+ return tuple;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/message-impl.h b/_dbus_bindings/message-impl.h
new file mode 100644
index 0000000..f480ada
--- /dev/null
+++ b/_dbus_bindings/message-impl.h
@@ -0,0 +1,1064 @@
+/* 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.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef USING_DBG
+static void _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);
+}
+# define DBG_DUMP_MESSAGE(x) _dbg_dump_message(x)
+#else
+# define DBG_DUMP_MESSAGE(x) do {} while(0)
+#endif
+
+static PyTypeObject MessageType, SignalMessageType, ErrorMessageType;
+static PyTypeObject MethodReturnMessageType, MethodCallMessageType;
+
+static inline int Message_Check (PyObject *o)
+{
+ return (o->ob_type == &MessageType)
+ || PyObject_IsInstance(o, (PyObject *)&MessageType);
+}
+
+typedef struct {
+ PyObject_HEAD
+ DBusMessage *msg;
+} Message;
+
+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);
+ }
+ self->ob_type->tp_free ((PyObject *)self);
+}
+
+static PyObject *
+Message_tp_new (PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ Message *self;
+
+ self = (Message *)type->tp_alloc (type, 0);
+ if (!self) return NULL;
+ self->msg = NULL;
+ return (PyObject *)self;
+}
+
+PyDoc_STRVAR(MethodCallMessage_tp_doc, "A method-call message.\n\n"
+"MethodCallMessage(destination: str or None, path: str,\n"
+" interface: str or None, method: str)\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 && !_validate_bus_name(destination, 1, 1)) return -1;
+ if (!_validate_object_path(path)) return -1;
+ if (interface && !_validate_interface_name(interface)) return -1;
+ if (!_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"
+"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"
+"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 (!_validate_object_path(path)) return -1;
+ if (!_validate_interface_name(interface)) return -1;
+ if (!_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;
+}
+
+PyDoc_STRVAR(ErrorMessage_tp_doc, "An error message.\n\n"
+"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 (!_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;
+}
+
+static DBusMessage *
+Message_BorrowDBusMessage (PyObject *msg)
+{
+ if (!Message_Check (msg)) {
+ PyErr_SetString (PyExc_TypeError,
+ "A _dbus_bindings.Message instance is required");
+ return NULL;
+ }
+ if (!((Message *)msg)->msg) {
+ DBusException_UnusableMessage();
+ return NULL;
+ }
+ return ((Message *)msg)->msg;
+}
+
+static PyObject *
+Message_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, 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)
+{
+ DBusMessage *msg;
+ if (!self->msg) return DBusException_UnusableMessage();
+ msg = dbus_message_copy(self->msg);
+ if (!msg) return PyErr_NoMemory();
+ return Message_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)
+{
+ if (!self->msg) return DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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)
+{
+ if (!self->msg) return DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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)
+{
+ if (!self->msg) return DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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)
+{
+ if (!self->msg) return DBusException_UnusableMessage();
+ return PyInt_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)
+{
+ if (!self->msg) return DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_member (self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ if (!_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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_path (self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyObject_CallFunction((PyObject *)&ObjectPathType, "(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)
+{
+ char **paths, **ptr;
+ PyObject *ret = PyList_New(0);
+
+ if (!ret) return NULL;
+ if (!self->msg) {
+ Py_DECREF (ret);
+ return DBusException_UnusableMessage ();
+ }
+ if (!dbus_message_get_path_decomposed (self->msg, &paths)) {
+ Py_DECREF (ret);
+ return PyErr_NoMemory ();
+ }
+ if (!paths) {
+ Py_DECREF(ret);
+ Py_RETURN_NONE;
+ }
+ for (ptr = paths; *ptr; ptr++) {
+ PyObject *str = PyString_FromString (*ptr);
+
+ if (!str) {
+ Py_DECREF (ret);
+ ret = NULL;
+ break;
+ }
+ if (PyList_Append (ret, str) < 0) {
+ Py_DECREF (ret);
+ ret = NULL;
+ break;
+ }
+ Py_DECREF (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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ 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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_signature (self->msg);
+ if (!c_str) {
+ return PyObject_CallFunction((PyObject *)&SignatureType, "(s)", "");
+ }
+ return PyObject_CallFunction((PyObject *)&SignatureType, "(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 DBusException_UnusableMessage();
+ 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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_sender (self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ if (!_validate_bus_name(name, 1, 0)) 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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_destination(self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ if (!_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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_interface (self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(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 DBusException_UnusableMessage();
+ 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 DBusException_UnusableMessage();
+ if (!_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)
+{
+ const char *c_str;
+
+ if (!self->msg) return DBusException_UnusableMessage();
+ c_str = dbus_message_get_error_name (self->msg);
+ if (!c_str) {
+ Py_RETURN_NONE;
+ }
+ return PyString_FromString(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 DBusException_UnusableMessage();
+ if (!_validate_error_name(name)) return NULL;
+ if (!dbus_message_set_error_name(self->msg, name)) return PyErr_NoMemory();
+ Py_RETURN_NONE;
+}
+
+#include "message-append-impl.h"
+#include "message-get-args-impl.h"
+
+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", (PyCFunction)Message_get_args,
+ METH_VARARGS|METH_KEYWORDS, Message_get_args__doc__},
+ {"guess_signature", (PyCFunction)Message_guess_signature,
+ METH_VARARGS|METH_STATIC, Message_guess_signature__doc__},
+ {"append", (PyCFunction)Message_append,
+ METH_VARARGS|METH_KEYWORDS, 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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings.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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings.MethodCallMessage", /*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*/
+ 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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings.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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings.SignalMessage", /*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*/
+ 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 = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_dbus_bindings.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 */
+};
+
+static inline int
+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;
+}
+
+static inline int
+insert_message_types(PyObject *this_module)
+{
+ 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..801f23b
--- /dev/null
+++ b/_dbus_bindings/module.c
@@ -0,0 +1,139 @@
+/* Main module source for the _dbus_bindings extension.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#define INSIDE_DBUS_BINDINGS
+#include "dbus_bindings.h"
+
+PyDoc_STRVAR(module_doc, "");
+
+#include "debug-impl.h" /* DBG, USING_DBG, DBG_EXC */
+#include "generic-impl.h" /* Non D-Bus support code */
+#include "validation-impl.h" /* Interface name, etc., validation */
+#include "exceptions-impl.h" /* Exception base classes */
+#include "signature-impl.h" /* Signature and its custom iterator */
+#include "types-impl.h" /* IntNN, UIntNN, ObjectPath */
+#include "containers-impl.h" /* Array, Dict, Variant */
+#include "bytes-impl.h" /* Byte, ByteArray */
+#include "message-impl.h" /* Message and subclasses */
+#include "pending-call-impl.h" /* PendingCall */
+#include "conn-impl.h" /* Connection */
+#include "bus-impl.h" /* Bus */
+
+static PyMethodDef module_functions[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC
+init_dbus_bindings (void)
+{
+ PyObject *this_module;
+
+ if (!init_generic ()) return;
+ if (!init_exception_types ()) return;
+ if (!init_signature ()) return;
+ if (!init_types ()) return;
+ if (!init_container_types ()) return;
+ if (!init_byte_types ()) return;
+ if (!init_message_types ()) return;
+ if (!init_pending_call ()) return;
+ if (!init_conn_types ()) return;
+ if (!init_bus_types ()) return;
+
+ this_module = Py_InitModule3 ("_dbus_bindings", module_functions, module_doc);
+ if (!this_module) return;
+
+ if (!insert_exception_types (this_module)) return;
+ if (!insert_signature (this_module)) return;
+ if (!insert_types (this_module)) return;
+ if (!insert_container_types (this_module)) return;
+ if (!insert_byte_types (this_module)) return;
+ if (!insert_message_types (this_module)) return;
+ if (!insert_pending_call (this_module)) return;
+ if (!insert_conn_types (this_module)) return;
+ if (!insert_bus_types (this_module)) return;
+
+#define ADD_CONST_VAL(x, v) \
+ if (PyModule_AddIntConstant (this_module, x, v) < 0) abort();
+#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(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)
+ 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)
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/pending-call-impl.h b/_dbus_bindings/pending-call-impl.h
new file mode 100644
index 0000000..c0bca56
--- /dev/null
+++ b/_dbus_bindings/pending-call-impl.h
@@ -0,0 +1,230 @@
+/* Implementation of PendingCall helper type for D-Bus bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(PendingCall_tp_doc,
+"Object representing a pending D-Bus call, returned by\n"
+"Connection._send_with_reply(). Cannot be instantiated directly.\n"
+);
+
+static PyTypeObject PendingCallType;
+
+static inline int PendingCall_Check (PyObject *o)
+{
+ return (o->ob_type == &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)
+{
+ 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. As a result, it's\n"
+"probably a bad idea.\n");
+static PyObject *
+PendingCall__block(PendingCall *self, PyObject *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 *handler)
+{
+ PyGILState_STATE gil = PyGILState_Ensure();
+ DBusMessage *msg = dbus_pending_call_steal_reply(pc);
+ Message *msg_obj;
+
+ 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 {
+ msg_obj = (Message *)Message_ConsumeDBusMessage(msg);
+ if (msg_obj) {
+ Py_XDECREF(PyObject_CallFunctionObjArgs(handler, msg_obj, NULL));
+ }
+ /* else OOM has happened - not a lot we can do about that,
+ * except possibly making it fatal (FIXME?) */
+ }
+
+ 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)
+{
+ 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. */
+static PyObject *
+PendingCall_ConsumeDBusPendingCall (DBusPendingCall *pc, PyObject *callable)
+{
+ dbus_bool_t ret;
+ PendingCall *self = PyObject_New(PendingCall, &PendingCallType);
+
+ if (!self) {
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_cancel(pc);
+ dbus_pending_call_unref(pc);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+
+ Py_INCREF(callable);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = dbus_pending_call_set_notify(pc,
+ (DBusPendingCallNotifyFunction)_pending_call_notify_function,
+ (void *)callable, (DBusFreeFunction)Glue_TakeGILAndXDecref);
+ Py_END_ALLOW_THREADS
+
+ if (!ret) {
+ PyErr_NoMemory();
+ Py_DECREF(callable);
+ Py_DECREF(self);
+ Py_BEGIN_ALLOW_THREADS
+ dbus_pending_call_cancel(pc);
+ dbus_pending_call_unref(pc);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+ 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 = {
+ PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+ 0,
+ "_dbus_bindings.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 */
+};
+
+static inline int
+init_pending_call (void)
+{
+ if (PyType_Ready (&PendingCallType) < 0) return 0;
+ return 1;
+}
+
+static inline int
+insert_pending_call (PyObject *this_module)
+{
+ 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/signature-impl.h b/_dbus_bindings/signature-impl.h
new file mode 100644
index 0000000..eda3177
--- /dev/null
+++ b/_dbus_bindings/signature-impl.h
@@ -0,0 +1,238 @@
+/* Implementation of Signature type for D-Bus bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+PyDoc_STRVAR(Signature_tp_doc,
+"Signature(str) -> Signature\n"
+"\n"
+"Signature is 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"
+);
+
+static PyTypeObject SignatureType;
+
+static inline int Signature_Check(PyObject *o)
+{
+ return (o->ob_type == &SignatureType)
+ || PyObject_IsInstance(o, (PyObject *)&SignatureType);
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *string;
+ DBusSignatureIter iter;
+} SignatureIter;
+
+static void
+SignatureIter_tp_dealloc (SignatureIter *self)
+{
+ Py_XDECREF(self->string);
+ self->string = NULL;
+ PyObject_Del(self);
+}
+
+static PyObject *
+SignatureIter_tp_iternext (SignatureIter *self)
+{
+ char *sig;
+ PyObject *obj;
+
+ /* Stop immediately if finished or not correctly initialized */
+ if (!self->string) return NULL;
+
+ sig = dbus_signature_iter_get_signature(&(self->iter));
+ if (!sig) return PyErr_NoMemory();
+ obj = PyObject_CallFunction((PyObject *)&SignatureType, "s", sig);
+ dbus_free(sig);
+ if (!obj) return NULL;
+
+ if (!dbus_signature_iter_next(&(self->iter))) {
+ /* mark object as having been finished with */
+ Py_DECREF(self->string);
+ self->string = NULL;
+ }
+
+ return obj;
+}
+
+static PyObject *
+SignatureIter_tp_iter(PyObject *self)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyTypeObject SignatureIterType = {
+ PyObject_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);
+ if (!iter) return NULL;
+
+ if (PyString_AS_STRING (self)[0]) {
+ Py_INCREF(self);
+ iter->string = self;
+ dbus_signature_iter_init(&(iter->iter), PyString_AS_STRING(self));
+ }
+ else {
+ /* this is a null string, make a null iterator */
+ iter->string = NULL;
+ }
+ return (PyObject *)iter;
+}
+
+static PyObject *
+Signature_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *tuple, *self;
+ const char *str = NULL;
+ static char *argnames[] = {"object_path", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:__new__", argnames,
+ &str)) return NULL;
+ if (!dbus_signature_validate(str, NULL)) {
+ PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
+ return NULL;
+ }
+ tuple = Py_BuildValue("(s)", str);
+ if (!tuple) return NULL;
+ self = PyString_Type.tp_new(cls, tuple, NULL);
+ Py_DECREF(tuple);
+ return self;
+}
+
+static PyTypeObject SignatureType = {
+ PyObject_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 */
+ str_subclass_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 */
+ 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(&PyString_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 */
+};
+
+static inline int
+init_signature(void)
+{
+ if (PyType_Ready(&SignatureIterType) < 0) return 0;
+
+ SignatureType.tp_base = &PyString_Type;
+ if (PyType_Ready(&SignatureType) < 0) return 0;
+ /* disable the tp_print copied from PyString_Type, so tp_repr gets called as
+ desired */
+ SignatureType.tp_print = NULL;
+
+ return 1;
+}
+
+static inline int
+insert_signature (PyObject *this_module)
+{
+ Py_INCREF(&SignatureType);
+ if (PyModule_AddObject(this_module, "Signature",
+ (PyObject *)&SignatureType) < 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/test.py b/_dbus_bindings/test.py
new file mode 100644
index 0000000..08f0fd0
--- /dev/null
+++ b/_dbus_bindings/test.py
@@ -0,0 +1,30 @@
+import unittest
+
+from _dbus_bindings import Int32, Int64, ObjectPath
+from _dbus_bindings import Message, SignalMessage
+
+class TestArgs(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def testMisc(self):
+ self.assertEquals(Message.guess_signature('abc', 123), 'si')
+
+ m = SignalMessage('/', 'com.example.Stuff', 'Done')
+ self.assertEquals(m.get_signature(), '')
+ m.extend('abc', 123, signature='si')
+ self.assertEquals(m.get_args(), ('abc', Int32(123)))
+ self.assertEquals(m.get_signature(), 'si')
+ self.assert_(m.has_signature('si'))
+ self.assert_(not m.has_signature('sx'))
+
+ m = SignalMessage('/', 'com.example.Stuff', 'Done')
+ m.extend('abc', 123)
+ self.assertEquals(m.get_args(), ('abc', Int32(123)))
+ self.assertEquals(m.get_signature(), 'si')
+ m.extend(('/foo', 1), signature='(ox)')
+ self.assertEquals(m.get_args(), (u'abc', Int32(123),
+ (ObjectPath('/foo'), Int64(1L))))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/_dbus_bindings/types-impl.h b/_dbus_bindings/types-impl.h
new file mode 100644
index 0000000..e69d460
--- /dev/null
+++ b/_dbus_bindings/types-impl.h
@@ -0,0 +1,635 @@
+/* Simple D-Bus types: integers of various sizes, and ObjectPath.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdint.h>
+
+/* IntNN, UIntNN ==================================================== */
+
+static PyTypeObject Int16Type, Int32Type, Int64Type;
+static PyTypeObject UInt16Type, UInt32Type, UInt64Type;
+static PyTypeObject ObjectPathType;
+
+#define DEFINE_CHECK(type) \
+static inline int type##_Check (PyObject *o) \
+{ \
+ return (o->ob_type == &type##Type) \
+ || PyObject_IsInstance(o, (PyObject *)&type##Type); \
+}
+DEFINE_CHECK(Int16)
+DEFINE_CHECK(Int32)
+DEFINE_CHECK(Int64)
+DEFINE_CHECK(UInt16)
+DEFINE_CHECK(UInt32)
+DEFINE_CHECK(UInt64)
+DEFINE_CHECK(ObjectPath)
+#undef DEFINE_CHECK
+
+/* The Int and UInt types are nice and simple.
+FIXME: use Python int as base for UInt32 and Int64 on 64-bit platforms?
+*/
+
+PyDoc_STRVAR(Int16_tp_doc,
+"A signed 16-bit integer (a subtype of int).");
+
+PyDoc_STRVAR(UInt16_tp_doc,
+"An unsigned 16-bit integer (a subtype of int).");
+
+PyDoc_STRVAR(Int32_tp_doc,
+"A signed 32-bit integer (a subtype of int).");
+
+PyDoc_STRVAR(UInt32_tp_doc,
+"An unsigned 32-bit integer (a subtype of long).");
+
+PyDoc_STRVAR(Int64_tp_doc,
+"A signed 16-bit integer (a subtype of long).");
+
+PyDoc_STRVAR(UInt64_tp_doc,
+"An unsigned 64-bit integer (a subtype of long).");
+
+static dbus_int16_t
+int16_range_check(PyObject *obj)
+{
+ long i = PyInt_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 i;
+}
+
+static PyObject *
+Int16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyInt_Type.tp_new)(cls, args, kwargs);
+ if (self && int16_range_check(self) == -1 && PyErr_Occurred()) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ return self;
+}
+
+static PyTypeObject Int16Type = {
+ PyObject_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 */
+ int_subclass_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 */
+ 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(&PyInt_Type), /* 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 */
+};
+
+static dbus_uint16_t
+uint16_range_check(PyObject *obj)
+{
+ long i = PyInt_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 i;
+}
+
+static PyObject *
+UInt16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyInt_Type.tp_new)(cls, args, kwargs);
+ if (self && uint16_range_check(self) == (dbus_uint16_t)(-1)
+ && PyErr_Occurred()) {
+ Py_DECREF (self);
+ return NULL;
+ }
+ return self;
+}
+
+static PyTypeObject UInt16Type = {
+ PyObject_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 */
+ int_subclass_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 */
+ 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(&PyInt_Type), /* 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 */
+};
+
+static dbus_int32_t
+int32_range_check(PyObject *obj)
+{
+ long i = PyInt_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 i;
+}
+
+static PyObject *
+Int32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyInt_Type.tp_new)(cls, args, kwargs);
+ if (int32_range_check(self) == -1 && PyErr_Occurred()) return NULL;
+ return self;
+}
+
+static PyTypeObject Int32Type = {
+ PyObject_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 */
+ int_subclass_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 */
+ 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(&PyInt_Type), /* 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 */
+};
+
+static dbus_uint32_t
+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_DECREF(long_obj);
+ return (dbus_uint32_t)(-1);
+ }
+ if (i < 0 || i > UINT32_MAX) {
+ PyErr_Format(PyExc_OverflowError, "Value %d out of range for UInt32",
+ (int)i);
+ Py_DECREF(long_obj);
+ return (dbus_uint32_t)(-1);
+ }
+ Py_DECREF(long_obj);
+ return i;
+}
+
+static PyObject *
+UInt32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyLong_Type.tp_new)(cls, args, kwargs);
+ if (self && uint32_range_check(self) == (dbus_uint32_t)(-1)
+ && PyErr_Occurred()) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ return self;
+}
+
+static PyTypeObject UInt32Type = {
+ PyObject_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 */
+ long_subclass_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 */
+ 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(&PyLong_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 */
+};
+
+#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
+
+static dbus_int64_t
+int64_range_check(PyObject *obj)
+{
+ unsigned long i;
+ PyObject *long_obj = PyNumber_Long(obj);
+
+ if (!long_obj) return -1;
+ i = PyLong_AsLongLong(long_obj);
+ if (i == -1 && PyErr_Occurred()) {
+ Py_DECREF(long_obj);
+ return -1;
+ }
+ if (i < INT64_MIN || i > INT64_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "Value out of range for Int64");
+ Py_DECREF(long_obj);
+ return -1;
+ }
+ Py_DECREF(long_obj);
+ return i;
+}
+
+static PyObject *
+Int64_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyLong_Type.tp_new)(cls, args, kwargs);
+ if (self && int64_range_check(self) == -1 && PyErr_Occurred()) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ return self;
+}
+
+static PyTypeObject Int64Type = {
+ PyObject_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 */
+ long_subclass_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 */
+ 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(&PyLong_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 */
+};
+
+static dbus_uint64_t
+uint64_range_check(PyObject *obj)
+{
+ unsigned 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 long long)(-1) && PyErr_Occurred()) {
+ Py_DECREF(long_obj);
+ return (dbus_uint64_t)(-1);
+ }
+ if (i < 0 || i > UINT64_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "Value out of range for UInt64");
+ Py_DECREF(long_obj);
+ return (dbus_uint64_t)(-1);
+ }
+ Py_DECREF(long_obj);
+ return i;
+}
+
+static PyObject *
+UInt64_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self = (PyLong_Type.tp_new)(cls, args, kwargs);
+ if (self && uint64_range_check(self) == (dbus_uint64_t)(-1)
+ && PyErr_Occurred()) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ return self;
+}
+
+static PyTypeObject UInt64Type = {
+ PyObject_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 */
+ long_subclass_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 */
+ 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(&PyLong_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 */
+};
+
+#endif /* defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG) */
+
+/* Object path ====================================================== */
+
+PyDoc_STRVAR(ObjectPath_tp_doc,
+"ObjectPath(path: str)\n\n"
+"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");
+
+static PyObject *
+ObjectPath_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *tuple, *self;
+ const char *str = NULL;
+ static char *argnames[] = {"object_path", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:__new__", argnames,
+ &str)) return NULL;
+ if (!_validate_object_path(str)) {
+ return NULL;
+ }
+ tuple = Py_BuildValue("(s)", str);
+ if (!tuple) return NULL;
+ self = PyString_Type.tp_new(cls, tuple, NULL);
+ Py_DECREF(tuple);
+ return self;
+}
+
+/* Slight subtlety: In conn-methods-impl.h we assume that object paths
+ * are nicely simple: in particular, that they can never reference
+ * other objects, and that they share strings' concept of equality
+ * and hash value. If you break these assumptions, alter
+ * _register_object_path and _unregister_object_path to coerce
+ * ObjectPaths into ordinary Python strings. */
+static PyTypeObject ObjectPathType = {
+ PyObject_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 */
+ str_subclass_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 */
+ 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(&PyString_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 */
+};
+
+static inline int
+init_types(void)
+{
+ Int16Type.tp_base = &PyInt_Type;
+ if (PyType_Ready(&Int16Type) < 0) return 0;
+ /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
+ desired */
+ Int16Type.tp_print = NULL;
+
+ UInt16Type.tp_base = &PyInt_Type;
+ if (PyType_Ready(&UInt16Type) < 0) return 0;
+ UInt16Type.tp_print = NULL;
+
+ Int32Type.tp_base = &PyInt_Type;
+ if (PyType_Ready(&Int32Type) < 0) return 0;
+ Int32Type.tp_print = NULL;
+
+ UInt32Type.tp_base = &PyLong_Type;
+ if (PyType_Ready(&UInt32Type) < 0) return 0;
+ UInt32Type.tp_print = NULL;
+
+ Int64Type.tp_base = &PyLong_Type;
+ if (PyType_Ready(&Int64Type) < 0) return 0;
+ Int64Type.tp_print = NULL;
+
+ UInt64Type.tp_base = &PyLong_Type;
+ if (PyType_Ready(&UInt64Type) < 0) return 0;
+ UInt64Type.tp_print = NULL;
+
+ ObjectPathType.tp_base = &PyString_Type;
+ if (PyType_Ready(&ObjectPathType) < 0) return 0;
+ ObjectPathType.tp_print = NULL;
+
+ return 1;
+}
+
+static inline int
+insert_types(PyObject *this_module)
+{
+ Py_INCREF(&Int16Type);
+ Py_INCREF(&UInt16Type);
+ Py_INCREF(&Int32Type);
+ Py_INCREF(&UInt32Type);
+ Py_INCREF(&Int64Type);
+ Py_INCREF(&UInt64Type);
+ if (PyModule_AddObject(this_module, "Int16",
+ (PyObject *)&Int16Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt16",
+ (PyObject *)&UInt16Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "Int32",
+ (PyObject *)&Int32Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt32",
+ (PyObject *)&UInt32Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "Int64",
+ (PyObject *)&Int64Type) < 0) return 0;
+ if (PyModule_AddObject(this_module, "UInt64",
+ (PyObject *)&UInt64Type) < 0) return 0;
+
+ Py_INCREF(&ObjectPathType);
+ if (PyModule_AddObject(this_module, "ObjectPath",
+ (PyObject *)&ObjectPathType) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/_dbus_bindings/validation-impl.h b/_dbus_bindings/validation-impl.h
new file mode 100644
index 0000000..9762fcb
--- /dev/null
+++ b/_dbus_bindings/validation-impl.h
@@ -0,0 +1,241 @@
+/* Implementation of various validation functions for use in dbus-python.
+ *
+ * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+static dbus_bool_t _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;
+}
+
+static dbus_bool_t _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;
+}
+
+static dbus_bool_t _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;
+}
+
+static inline dbus_bool_t _validate_error_name(const char *name)
+{
+ return _validate_interface_name(name);
+}
+
+static dbus_bool_t _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: */
diff --git a/_dbus_glib_bindings/module.c b/_dbus_glib_bindings/module.c
new file mode 100644
index 0000000..4a225f2
--- /dev/null
+++ b/_dbus_glib_bindings/module.c
@@ -0,0 +1,74 @@
+/* Glue code to attach the GObject main loop to D-Bus from within Python.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <Python.h>
+#include "dbus_bindings.h"
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+PyDoc_STRVAR(module_doc, "");
+
+PyDoc_STRVAR(setup_with_g_main__doc__,
+"setup_with_g_main(conn: dbus.Connection)");
+static PyObject *
+setup_with_g_main (PyObject *unused, PyObject *args)
+{
+ DBusConnection *dbc;
+ PyObject *conn;
+ if (!PyArg_ParseTuple(args, "O:setup_with_g_main", &conn)) return NULL;
+
+ dbc = Connection_BorrowDBusConnection (conn);
+ if (!dbc) return NULL;
+ dbus_connection_setup_with_g_main (dbc, NULL);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gthreads_init__doc__,
+"gthreads_init()");
+static PyObject *
+gthreads_init (PyObject *unused, PyObject *also_unused)
+{
+ dbus_g_thread_init();
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef module_functions[] = {
+ {"setup_with_g_main", setup_with_g_main, METH_VARARGS,
+ setup_with_g_main__doc__},
+ {"gthreads_init", gthreads_init, METH_NOARGS, gthreads_init__doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC
+init_dbus_glib_bindings (void)
+{
+ PyObject *this_module;
+
+ if (import_dbus_bindings () < 0) return;
+ this_module = Py_InitModule3 ("_dbus_glib_bindings", module_functions,
+ module_doc);
+ if (!this_module) return;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
diff --git a/include/dbus_bindings.h b/include/dbus_bindings.h
new file mode 100644
index 0000000..8b11585
--- /dev/null
+++ b/include/dbus_bindings.h
@@ -0,0 +1,64 @@
+/* C API for _dbus_bindings, used by _dbus_glib_bindings.
+ *
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_BINDINGS_H
+#define DBUS_BINDINGS_H
+
+#define DBUS_API_SUBJECT_TO_CHANGE 1
+#include <dbus/dbus.h>
+
+DBUS_BEGIN_DECLS
+
+#ifdef INSIDE_DBUS_BINDINGS
+
+static DBusConnection *Connection_BorrowDBusConnection (PyObject *);
+
+#else
+
+static void **dbus_bindings_API;
+#define Connection_BorrowDBusConnection \
+ (*(DBusConnection *(*)(PyObject *))dbus_bindings_API[0])
+static int
+import_dbus_bindings(void)
+{
+ PyObject *module = PyImport_ImportModule ("_dbus_bindings");
+
+ if (module != NULL)
+ {
+ PyObject *c_api = PyObject_GetAttrString (module, "_C_API");
+ if (c_api == NULL) return -1;
+ if (PyCObject_Check (c_api))
+ {
+ dbus_bindings_API = (void **)PyCObject_AsVoidPtr (c_api);
+ }
+ Py_DECREF (c_api);
+ }
+ return 0;
+}
+
+#endif
+
+DBUS_END_DECLS
+
+#endif