Actually commit the numerous copyright-statement changes.
[dbus-python-phuang.git] / _dbus_bindings / conn-methods.c
blob09fc87305028c71f97a3d5702fa9513ea803f652
1 /* Implementation of normal Python-accessible methods on the _dbus_bindings
2  * Connection type; separated out to keep the file size manageable.
3  *
4  * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
24 #include "dbus_bindings-internal.h"
25 #include "conn-internal.h"
27 static void
28 _object_path_unregister(DBusConnection *conn, void *user_data)
30     PyGILState_STATE gil = PyGILState_Ensure();
31     PyObject *tuple = NULL;
32     Connection *conn_obj = NULL;
33     PyObject *callable;
35     conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
36     if (!conn_obj) goto out;
37     TRACE(conn_obj);
39     DBG("Connection at %p unregistering object path %s",
40         conn_obj, PyString_AS_STRING((PyObject *)user_data));
41     tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data);
42     if (!tuple) goto out;
43     if (tuple == Py_None) goto out;
45     DBG("%s", "... yes we have handlers for that object path");
47     /* 0'th item is the unregisterer (if that's a word) */
48     callable = PyTuple_GetItem(tuple, 0);
49     if (callable && callable != Py_None) {
50         DBG("%s", "... and we even have an unregisterer");
51         /* any return from the unregisterer is ignored */
52         Py_XDECREF(PyObject_CallFunctionObjArgs(callable, conn_obj, NULL));
53     }
54 out:
55     Py_XDECREF(conn_obj);
56     Py_XDECREF(tuple);
57     /* the user_data (a Python str) is no longer ref'd by the DBusConnection */
58     Py_XDECREF((PyObject *)user_data);
59     if (PyErr_Occurred()) {
60         PyErr_Print();
61     }
62     PyGILState_Release(gil);
65 static DBusHandlerResult
66 _object_path_message(DBusConnection *conn, DBusMessage *message,
67                      void *user_data)
69     DBusHandlerResult ret;
70     PyGILState_STATE gil = PyGILState_Ensure();
71     Connection *conn_obj = NULL;
72     PyObject *tuple = NULL;
73     PyObject *msg_obj;
74     PyObject *callable;             /* borrowed */
76     dbus_message_ref(message);
77     msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
78     if (!msg_obj) {
79         ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
80         goto out;
81     }
83     conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
84     if (!conn_obj) {
85         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
86         goto out;
87     }
88     TRACE(conn_obj);
90     DBG("Connection at %p messaging object path %s",
91         conn_obj, PyString_AS_STRING((PyObject *)user_data));
92     DBG_DUMP_MESSAGE(message);
93     tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data);
94     if (!tuple || tuple == Py_None) {
95         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
96         goto out;
97     }
99     DBG("%s", "... yes we have handlers for that object path");
101     /* 1st item (0-based) is the message callback */
102     callable = PyTuple_GetItem(tuple, 1);
103     if (!callable) {
104         DBG("%s", "... error getting message handler from tuple");
105         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
106     }
107     else if (callable == Py_None) {
108         /* there was actually no handler after all */
109         DBG("%s", "... but those handlers don't do messages");
110         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
111     }
112     else {
113         DBG("%s", "... and we have a message handler for that object path");
114         ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
115     }
117 out:
118     Py_XDECREF(msg_obj);
119     Py_XDECREF(conn_obj);
120     Py_XDECREF(tuple);
121     if (PyErr_Occurred()) {
122         PyErr_Print();
123     }
124     PyGILState_Release(gil);
125     return ret;
128 static const DBusObjectPathVTable _object_path_vtable = {
129     _object_path_unregister,
130     _object_path_message,
133 static DBusHandlerResult
134 _filter_message(DBusConnection *conn, DBusMessage *message, void *user_data)
136     DBusHandlerResult ret;
137     PyGILState_STATE gil = PyGILState_Ensure();
138     Connection *conn_obj = NULL;
139     PyObject *callable = NULL;
140     PyObject *msg_obj;
141 #ifndef DBUS_PYTHON_DISABLE_CHECKS
142     Py_ssize_t i, size;
143 #endif
145     dbus_message_ref(message);
146     msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
147     if (!msg_obj) {
148         DBG("%s", "OOM while trying to construct Message");
149         ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
150         goto out;
151     }
153     conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
154     if (!conn_obj) {
155         DBG("%s", "failed to traverse DBusConnection -> Connection weakref");
156         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
157         goto out;
158     }
159     TRACE(conn_obj);
161     /* The user_data is a pointer to a Python object. To avoid
162      * cross-library reference cycles, the DBusConnection isn't allowed
163      * to reference it. However, as long as the Connection is still
164      * alive, its ->filters list owns a reference to the same Python
165      * object, so the object should also still be alive.
166      *
167      * To ensure that this works, be careful whenever manipulating the
168      * filters list! (always put things in the list *before* giving
169      * them to libdbus, etc.)
170      */
171 #ifdef DBUS_PYTHON_DISABLE_CHECKS
172     callable = (PyObject *)user_data;
173 #else
174     size = PyList_GET_SIZE(conn_obj->filters);
175     for (i = 0; i < size; i++) {
176         callable = PyList_GET_ITEM(conn_obj->filters, i);
177         if (callable == user_data) {
178             Py_INCREF(callable);
179         }
180         else {
181             callable = NULL;
182         }
183     }
185     if (!callable) {
186         DBG("... filter %p has vanished from ->filters, so not calling it",
187             user_data);
188         ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
189         goto out;
190     }
191 #endif
193     ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
194 out:
195     Py_XDECREF(msg_obj);
196     Py_XDECREF(conn_obj);
197     Py_XDECREF(callable);
198     PyGILState_Release(gil);
199     return ret;
202 PyDoc_STRVAR(Connection__require_main_loop__doc__,
203 "_require_main_loop()\n\n"
204 "Raise an exception if this Connection is not bound to any main loop -\n"
205 "in this state, asynchronous calls, receiving signals and exporting objects\n"
206 "will not work.\n"
207 "\n"
208 "`dbus.mainloop.NULL_MAIN_LOOP` is treated like a valid main loop - if you're\n"
209 "using that, you presumably know what you're doing.\n");
210 static PyObject *
211 Connection__require_main_loop (Connection *self, PyObject *args UNUSED)
213     if (!self->has_mainloop) {
214         PyErr_SetString(PyExc_RuntimeError,
215                         "To make asynchronous calls, receive signals or "
216                         "export objects, D-Bus connections must be attached "
217                         "to a main loop by passing mainloop=... to the "
218                         "constructor or calling "
219                         "dbus.set_default_main_loop(...)");
220         return NULL;
221     }
222     Py_RETURN_NONE;
225 PyDoc_STRVAR(Connection_close__doc__,
226 "close()\n\n"
227 "Close the connection.");
228 static PyObject *
229 Connection_close (Connection *self, PyObject *args)
231     TRACE(self);
232     if (!PyArg_ParseTuple(args, ":close")) return NULL;
233     /* Because the user explicitly asked to close the connection, we'll even
234     let them close shared connections. */
235     if (self->conn) {
236         Py_BEGIN_ALLOW_THREADS
237         dbus_connection_close(self->conn);
238         Py_END_ALLOW_THREADS
239     }
240     Py_RETURN_NONE;
243 PyDoc_STRVAR(Connection_get_is_connected__doc__,
244 "get_is_connected() -> bool\n\n"
245 "Return true if this Connection is connected.\n");
246 static PyObject *
247 Connection_get_is_connected (Connection *self, PyObject *args)
249     dbus_bool_t ret;
251     TRACE(self);
252     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
253     if (!PyArg_ParseTuple(args, ":get_is_connected")) return NULL;
254     Py_BEGIN_ALLOW_THREADS
255     ret = dbus_connection_get_is_connected(self->conn);
256     Py_END_ALLOW_THREADS
257     return PyBool_FromLong(ret);
260 PyDoc_STRVAR(Connection_get_is_authenticated__doc__,
261 "get_is_authenticated() -> bool\n\n"
262 "Return true if this Connection was ever authenticated.\n");
263 static PyObject *
264 Connection_get_is_authenticated (Connection *self, PyObject *args)
266     dbus_bool_t ret;
268     TRACE(self);
269     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
270     if (!PyArg_ParseTuple(args, ":get_is_authenticated")) return NULL;
271     Py_BEGIN_ALLOW_THREADS
272     ret = dbus_connection_get_is_authenticated(self->conn);
273     Py_END_ALLOW_THREADS
274     return PyBool_FromLong(ret);
277 PyDoc_STRVAR(Connection_set_exit_on_disconnect__doc__,
278 "set_exit_on_disconnect(bool)\n\n"
279 "Set whether the C function ``_exit`` will be called when this Connection\n"
280 "becomes disconnected. This will cause the program to exit without calling\n"
281 "any cleanup code or exit handlers.\n"
282 "\n"
283 "The default is for this feature to be disabled for Connections and enabled\n"
284 "for Buses.\n");
285 static PyObject *
286 Connection_set_exit_on_disconnect (Connection *self, PyObject *args)
288     int exit_on_disconnect;
290     TRACE(self);
291     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
292     if (!PyArg_ParseTuple(args, "i:set_exit_on_disconnect",
293                           &exit_on_disconnect)) {
294         return NULL;
295     }
296     Py_BEGIN_ALLOW_THREADS
297     dbus_connection_set_exit_on_disconnect(self->conn,
298                                            exit_on_disconnect ? 1 : 0);
299     Py_END_ALLOW_THREADS
300     Py_RETURN_NONE;
303 PyDoc_STRVAR(Connection_send_message__doc__,
304 "send_message(msg) -> long\n\n"
305 "Queue the given message for sending, and return the message serial number.\n"
306 "\n"
307 ":Parameters:\n"
308 "   `msg` : dbus.lowlevel.Message\n"
309 "       The message to be sent.\n"
311 static PyObject *
312 Connection_send_message(Connection *self, PyObject *args)
314     dbus_bool_t ok;
315     PyObject *obj;
316     DBusMessage *msg;
317     dbus_uint32_t serial;
319     TRACE(self);
320     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
321     if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
323     msg = DBusPyMessage_BorrowDBusMessage(obj);
324     if (!msg) return NULL;
326     Py_BEGIN_ALLOW_THREADS
327     ok = dbus_connection_send(self->conn, msg, &serial);
328     Py_END_ALLOW_THREADS
330     if (!ok) {
331         return PyErr_NoMemory();
332     }
334     return PyLong_FromUnsignedLong(serial);
337 /* The timeout is in seconds here, since that's conventional in Python. */
338 PyDoc_STRVAR(Connection_send_message_with_reply__doc__,
339 "send_message_with_reply(msg, reply_handler, timeout_s=-1, "
340 "require_main_loop=False) -> dbus.lowlevel.PendingCall\n\n"
341 "Queue the message for sending; expect a reply via the returned PendingCall,\n"
342 "which can also be used to cancel the pending call.\n"
343 "\n"
344 ":Parameters:\n"
345 "   `msg` : dbus.lowlevel.Message\n"
346 "       The message to be sent\n"
347 "   `reply_handler` : callable\n"
348 "       Asynchronous reply handler: will be called with one positional\n"
349 "       parameter, a Message instance representing the reply.\n"
350 "   `timeout_s` : float\n"
351 "       If the reply takes more than this many seconds, a timeout error\n"
352 "       will be created locally and raised instead. If this timeout is\n"
353 "       negative (default), a sane default (supplied by libdbus) is used.\n"
354 "   `require_main_loop` : bool\n"
355 "       If True, raise RuntimeError if this Connection does not have a main\n"
356 "       loop configured. If False (default) and there is no main loop, you are\n"
357 "       responsible for calling block() on the PendingCall.\n"
358 "\n"
360 static PyObject *
361 Connection_send_message_with_reply(Connection *self, PyObject *args, PyObject *kw)
363     dbus_bool_t ok;
364     double timeout_s = -1.0;
365     int timeout_ms;
366     PyObject *obj, *callable;
367     DBusMessage *msg;
368     DBusPendingCall *pending;
369     int require_main_loop = 0;
370     static char *argnames[] = {"msg", "reply_handler", "timeout_s",
371                                "require_main_loop", NULL};
373     TRACE(self);
374     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
375     if (!PyArg_ParseTupleAndKeywords(args, kw,
376                                      "OO|fi:send_message_with_reply",
377                                      argnames,
378                                      &obj, &callable, &timeout_s,
379                                      &require_main_loop)) {
380         return NULL;
381     }
382     if (require_main_loop && !Connection__require_main_loop(self, NULL)) {
383         return NULL;
384     }
386     msg = DBusPyMessage_BorrowDBusMessage(obj);
387     if (!msg) return NULL;
389     if (timeout_s < 0) {
390         timeout_ms = -1;
391     }
392     else {
393         if (timeout_s > ((double)INT_MAX) / 1000.0) {
394             PyErr_SetString(PyExc_ValueError, "Timeout too long");
395             return NULL;
396         }
397         timeout_ms = (int)(timeout_s * 1000.0);
398     }
400     Py_BEGIN_ALLOW_THREADS
401     ok = dbus_connection_send_with_reply(self->conn, msg, &pending,
402                                          timeout_ms);
403     Py_END_ALLOW_THREADS
405     if (!ok) {
406         return PyErr_NoMemory();
407     }
409     return DBusPyPendingCall_ConsumeDBusPendingCall(pending, callable);
412 /* Again, the timeout is in seconds, since that's conventional in Python. */
413 PyDoc_STRVAR(Connection_send_message_with_reply_and_block__doc__,
414 "send_message_with_reply_and_block(msg, timeout_s=-1)"
415 " -> dbus.lowlevel.Message\n\n"
416 "Send the message and block while waiting for a reply.\n"
417 "\n"
418 "This does not re-enter the main loop, so it can lead to a deadlock, if\n"
419 "the called method tries to make a synchronous call to a method in this\n"
420 "application. As such, it's probably a bad idea.\n"
421 "\n"
422 ":Parameters:\n"
423 "   `msg` : dbus.lowlevel.Message\n"
424 "       The message to be sent\n"
425 "   `timeout_s` : float\n"
426 "       If the reply takes more than this many seconds, a timeout error\n"
427 "       will be created locally and raised instead. If this timeout is\n"
428 "       negative (default), a sane default (supplied by libdbus) is used.\n"
429 ":Returns:\n"
430 "   A `dbus.lowlevel.Message` instance (probably a `dbus.lowlevel.MethodReturnMessage`) on success\n"
431 ":Raises dbus.DBusException:\n"
432 "   On error (including if the reply arrives but is an\n"
433 "   error message)\n"
434 "\n"
436 static PyObject *
437 Connection_send_message_with_reply_and_block(Connection *self, PyObject *args)
439     double timeout_s = -1.0;
440     int timeout_ms;
441     PyObject *obj;
442     DBusMessage *msg, *reply;
443     DBusError error;
445     TRACE(self);
446     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
447     if (!PyArg_ParseTuple(args, "O|f:send_message_with_reply_and_block", &obj,
448                           &timeout_s)) {
449         return NULL;
450     }
452     msg = DBusPyMessage_BorrowDBusMessage(obj);
453     if (!msg) return NULL;
455     if (timeout_s < 0) {
456         timeout_ms = -1;
457     }
458     else {
459         if (timeout_s > ((double)INT_MAX) / 1000.0) {
460             PyErr_SetString(PyExc_ValueError, "Timeout too long");
461             return NULL;
462         }
463         timeout_ms = (int)(timeout_s * 1000.0);
464     }
466     dbus_error_init(&error);
467     Py_BEGIN_ALLOW_THREADS
468     reply = dbus_connection_send_with_reply_and_block(self->conn, msg,
469                                                       timeout_ms, &error);
470     Py_END_ALLOW_THREADS
472     if (!reply) {
473         return DBusPyException_ConsumeError(&error);
474     }
475     return DBusPyMessage_ConsumeDBusMessage(reply);
478 PyDoc_STRVAR(Connection_flush__doc__,
479 "flush()\n\n"
480 "Block until the outgoing message queue is empty.\n");
481 static PyObject *
482 Connection_flush (Connection *self, PyObject *args UNUSED)
484     TRACE(self);
485     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
486     Py_BEGIN_ALLOW_THREADS
487     dbus_connection_flush (self->conn);
488     Py_END_ALLOW_THREADS
489     Py_RETURN_NONE;
492 /* Unsupported:
493  * dbus_connection_preallocate_send
494  * dbus_connection_free_preallocated_send
495  * dbus_connection_send_preallocated
496  * dbus_connection_borrow_message
497  * dbus_connection_return_message
498  * dbus_connection_steal_borrowed_message
499  * dbus_connection_pop_message
500  */
502 /* Non-main-loop handling not yet implemented: */
503     /* dbus_connection_read_write_dispatch */
504     /* dbus_connection_read_write */
506 /* Main loop handling not yet implemented: */
507     /* dbus_connection_get_dispatch_status */
508     /* dbus_connection_dispatch */
509     /* dbus_connection_set_watch_functions */
510     /* dbus_connection_set_timeout_functions */
511     /* dbus_connection_set_wakeup_main_function */
512     /* dbus_connection_set_dispatch_status_function */
514 /* Normally in Python this would be called fileno(), but I don't want to
515  * encourage people to select() on it */
516 PyDoc_STRVAR(Connection_get_unix_fd__doc__,
517 "get_unix_fd() -> int or None\n\n"
518 "Get the connection's UNIX file descriptor, if any.\n\n"
519 "This can be used for SELinux access control checks with ``getpeercon()``\n"
520 "for example. **Do not** read or write to the file descriptor, or try to\n"
521 "``select()`` on it.\n");
522 static PyObject *
523 Connection_get_unix_fd (Connection *self, PyObject *unused UNUSED)
525     int fd;
526     dbus_bool_t ok;
528     TRACE(self);
529     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
530     Py_BEGIN_ALLOW_THREADS
531     ok = dbus_connection_get_unix_fd (self->conn, &fd);
532     Py_END_ALLOW_THREADS
533     if (!ok) Py_RETURN_NONE;
534     return PyInt_FromLong(fd);
537 PyDoc_STRVAR(Connection_get_peer_unix_user__doc__,
538 "get_peer_unix_user() -> long or None\n\n"
539 "Get the UNIX user ID at the other end of the connection, if it has been\n"
540 "authenticated. Return None if this is a non-UNIX platform or the\n"
541 "connection has not been authenticated.\n");
542 static PyObject *
543 Connection_get_peer_unix_user (Connection *self, PyObject *unused UNUSED)
545     unsigned long uid;
546     dbus_bool_t ok;
548     TRACE(self);
549     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
550     Py_BEGIN_ALLOW_THREADS
551     ok = dbus_connection_get_unix_user (self->conn, &uid);
552     Py_END_ALLOW_THREADS
553     if (!ok) Py_RETURN_NONE;
554     return PyLong_FromUnsignedLong (uid);
557 PyDoc_STRVAR(Connection_get_peer_unix_process_id__doc__,
558 "get_peer_unix_process_id() -> long or None\n\n"
559 "Get the UNIX process ID at the other end of the connection, if it has been\n"
560 "authenticated. Return None if this is a non-UNIX platform or the\n"
561 "connection has not been authenticated.\n");
562 static PyObject *
563 Connection_get_peer_unix_process_id (Connection *self, PyObject *unused UNUSED)
565     unsigned long pid;
566     dbus_bool_t ok;
568     TRACE(self);
569     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
570     Py_BEGIN_ALLOW_THREADS
571     ok = dbus_connection_get_unix_process_id (self->conn, &pid);
572     Py_END_ALLOW_THREADS
573     if (!ok) Py_RETURN_NONE;
574     return PyLong_FromUnsignedLong (pid);
577 /* TODO: wrap dbus_connection_set_unix_user_function Pythonically */
579 PyDoc_STRVAR(Connection_add_message_filter__doc__,
580 "add_message_filter(callable)\n\n"
581 "Add the given message filter to the internal list.\n\n"
582 "Filters are handlers that are run on all incoming messages, prior to the\n"
583 "objects registered to handle object paths.\n"
584 "\n"
585 "Filters are run in the order that they were added. The same handler can\n"
586 "be added as a filter more than once, in which case it will be run more\n"
587 "than once. Filters added during a filter callback won't be run on the\n"
588 "message being processed.\n"
590 static PyObject *
591 Connection_add_message_filter(Connection *self, PyObject *callable)
593     dbus_bool_t ok;
595     TRACE(self);
596     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
597     /* The callable must be referenced by ->filters *before* it is
598      * given to libdbus, which does not own a reference to it.
599      */
600     if (PyList_Append(self->filters, callable) < 0) {
601         return NULL;
602     }
604     Py_BEGIN_ALLOW_THREADS
605     ok = dbus_connection_add_filter(self->conn, _filter_message, callable,
606                                     NULL);
607     Py_END_ALLOW_THREADS
609     if (!ok) {
610         Py_XDECREF(PyObject_CallMethod(self->filters, "remove", "(O)",
611                                        callable));
612         PyErr_NoMemory();
613         return NULL;
614     }
615     Py_RETURN_NONE;
618 PyDoc_STRVAR(Connection_remove_message_filter__doc__,
619 "remove_message_filter(callable)\n\n"
620 "Remove the given message filter (see `add_message_filter` for details).\n"
621 "\n"
622 ":Raises LookupError:\n"
623 "   The given callable is not among the registered filters\n");
624 static PyObject *
625 Connection_remove_message_filter(Connection *self, PyObject *callable)
627     PyObject *obj;
629     TRACE(self);
630     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
631     /* It's safe to do this before removing it from libdbus, because
632      * the presence of callable in our arguments means we have a ref
633      * to it. */
634     obj = PyObject_CallMethod(self->filters, "remove", "(O)", callable);
635     if (!obj) return NULL;
636     Py_DECREF(obj);
638     Py_BEGIN_ALLOW_THREADS
639     dbus_connection_remove_filter(self->conn, _filter_message, callable);
640     Py_END_ALLOW_THREADS
642     Py_RETURN_NONE;
645 PyDoc_STRVAR(Connection__register_object_path__doc__,
646 "register_object_path(path, on_message, on_unregister=None, fallback=False)\n"
647 "\n"
648 "Register a callback to be called when messages arrive at the given\n"
649 "object-path. Used to export objects' methods on the bus in a low-level\n"
650 "way. For the high-level interface to this functionality (usually\n"
651 "recommended) see the `dbus.service.Object` base class.\n"
652 "\n"
653 ":Parameters:\n"
654 "   `path` : str\n"
655 "       Object path to be acted on\n"
656 "   `on_message` : callable\n"
657 "       Called when a message arrives at the given object-path, with\n"
658 "       two positional parameters: the first is this Connection,\n"
659 "       the second is the incoming `dbus.lowlevel.Message`.\n"
660 "   `on_unregister` : callable or None\n"
661 "       If not None, called when the callback is unregistered.\n"
662 "   `fallback` : bool\n"
663 "       If True (the default is False), when a message arrives for a\n"
664 "       'subdirectory' of the given path and there is no more specific\n"
665 "       handler, use this handler. Normally this handler is only run if\n"
666 "       the paths match exactly.\n"
668 static PyObject *
669 Connection__register_object_path(Connection *self, PyObject *args,
670                                  PyObject *kwargs)
672     dbus_bool_t ok;
673     int fallback = 0;
674     PyObject *callbacks, *path, *tuple, *on_message, *on_unregister = Py_None;
675     static char *argnames[] = {"path", "on_message", "on_unregister",
676                                "fallback", NULL};
678     TRACE(self);
679     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
680     if (!Connection__require_main_loop(self, NULL)) {
681         return NULL;
682     }
683     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
684                                      "OO|Oi:_register_object_path",
685                                      argnames, 
686                                      &path,
687                                      &on_message, &on_unregister,
688                                      &fallback)) return NULL;
690     /* Take a reference to path, which we give away to libdbus in a moment.
692     Also, path needs to be a string (not a subclass which could do something
693     mad) to preserve the desirable property that the DBusConnection can
694     never strongly reference the Connection, even indirectly.
695     */
696     if (PyString_CheckExact(path)) {
697         Py_INCREF(path);
698     }
699     else if (PyUnicode_Check(path)) {
700         path = PyUnicode_AsUTF8String(path);
701         if (!path) return NULL;
702     }
703     else if (PyString_Check(path)) {
704         path = PyString_FromString(PyString_AS_STRING(path));
705         if (!path) return NULL;
706     }
707     else {
708         PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object");
709         return NULL;
710     }
712     if (!dbus_py_validate_object_path(PyString_AS_STRING(path))) {
713         Py_DECREF(path);
714         return NULL;
715     }
717     tuple = Py_BuildValue("(OO)", on_unregister, on_message);
718     if (!tuple) {
719         Py_DECREF(path);
720         return NULL;
721     }
723     /* Guard against registering a handler that already exists. */
724     callbacks = PyDict_GetItem(self->object_paths, path);
725     if (callbacks && callbacks != Py_None) {
726         PyErr_Format(PyExc_KeyError, "Can't register the object-path "
727                      "handler for '%s': there is already a handler",
728                      PyString_AS_STRING(path));
729         Py_DECREF(tuple);
730         Py_DECREF(path);
731         return NULL;
732     }
734     /* Pre-allocate a slot in the dictionary, so we know we'll be able
735      * to replace it with the callbacks without OOM.
736      * This ensures we can keep libdbus' opinion of whether those
737      * paths are handled in sync with our own. */
738     if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
739         Py_DECREF(tuple);
740         Py_DECREF(path);
741         return NULL;
742     }
744     Py_BEGIN_ALLOW_THREADS
745     if (fallback) {
746         ok = dbus_connection_register_fallback(self->conn,
747                                                PyString_AS_STRING(path),
748                                                &_object_path_vtable,
749                                                path);
750     }
751     else {
752         ok = dbus_connection_register_object_path(self->conn,
753                                                   PyString_AS_STRING(path),
754                                                   &_object_path_vtable,
755                                                   path);
756     }
757     Py_END_ALLOW_THREADS
759     if (ok) {
760         if (PyDict_SetItem(self->object_paths, path, tuple) < 0) {
761             /* That shouldn't have happened, we already allocated enough
762             memory for it. Oh well, try to undo the registration to keep
763             things in sync. If this fails too, we've leaked a bit of
764             memory in libdbus, but tbh we should never get here anyway. */
765             Py_BEGIN_ALLOW_THREADS
766             ok = dbus_connection_unregister_object_path(self->conn,
767                                                     PyString_AS_STRING(path));
768             Py_END_ALLOW_THREADS
769             return NULL;
770         }
771         /* don't DECREF path: libdbus owns a ref now */
772         Py_DECREF(tuple);
773         Py_RETURN_NONE;
774     }
775     else {
776         /* Oops, OOM. Tidy up, if we can, ignoring any error. */
777         PyDict_DelItem(self->object_paths, path);
778         PyErr_Clear();
779         Py_DECREF(tuple);
780         Py_DECREF(path);
781         PyErr_NoMemory();
782         return NULL;
783     }
786 PyDoc_STRVAR(Connection__unregister_object_path__doc__,
787 "unregister_object_path(path)\n\n"
788 "Remove a previously registered handler for the given object path.\n"
789 "\n"
790 ":Parameters:\n"
791 "   `path` : str\n"
792 "       The object path whose handler is to be removed\n"
793 ":Raises KeyError: if there is no handler registered for exactly that\n"
794 "   object path.\n"
796 static PyObject *
797 Connection__unregister_object_path(Connection *self, PyObject *args,
798                                    PyObject *kwargs)
800     dbus_bool_t ok;
801     PyObject *path;
802     PyObject *callbacks;
803     static char *argnames[] = {"path", NULL};
805     TRACE(self);
806     DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
807     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
808                                      "O:_unregister_object_path",
809                                      argnames, &path)) return NULL;
811     /* Take a ref to the path. Same comments as for _register_object_path. */
812     if (PyString_CheckExact(path)) {
813         Py_INCREF(path);
814     }
815     else if (PyUnicode_Check(path)) {
816         path = PyUnicode_AsUTF8String(path);
817         if (!path) return NULL;
818     }
819     else if (PyString_Check(path)) {
820         path = PyString_FromString(PyString_AS_STRING(path));
821         if (!path) return NULL;
822     }
823     else {
824         PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object");
825         return NULL;
826     }
828     /* Guard against unregistering a handler that doesn't, in fact, exist,
829     or whose unregistration is already in progress. */
830     callbacks = PyDict_GetItem(self->object_paths, path);
831     if (!callbacks || callbacks == Py_None) {
832         PyErr_Format(PyExc_KeyError, "Can't unregister the object-path "
833                      "handler for '%s': there is no such handler",
834                      PyString_AS_STRING(path));
835         Py_DECREF(path);
836         return NULL;
837     }
839     /* Hang on to a reference to the callbacks for the moment. */
840     Py_INCREF(callbacks);
842     /* Get rid of the object-path while we still have the GIL, to
843     guard against unregistering twice from different threads (which
844     causes undefined behaviour in libdbus).
846     Because deletion would make it possible for the re-insertion below
847     to fail, we instead set the handler to None as a placeholder.
848     */
849     if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
850         /* If that failed, there's no need to be paranoid as below - the
851         callbacks are still set, so we failed, but at least everything
852         is in sync. */
853         Py_DECREF(callbacks);
854         Py_DECREF(path);
855         return NULL;
856     }
857     
858     /* BEGIN PARANOIA
859     This is something of a critical section - the dict of object-paths
860     and libdbus' internal structures are out of sync for a bit. We have
861     to be able to cope with that.
863     It's really annoying that dbus_connection_unregister_object_path
864     can fail, *and* has undefined behaviour if the object path has
865     already been unregistered. Either/or would be fine.
866     */
868     Py_BEGIN_ALLOW_THREADS
869     ok = dbus_connection_unregister_object_path(self->conn,
870                                                 PyString_AS_STRING(path));
871     Py_END_ALLOW_THREADS
873     if (ok) {
874         Py_DECREF(callbacks);
875         PyDict_DelItem(self->object_paths, path);
876         /* END PARANOIA on successful code path */
877         /* The above can't fail unless by some strange trickery the key is no
878         longer present. Ignore any errors. */
879         Py_DECREF(path);
880         PyErr_Clear();
881         Py_RETURN_NONE;
882     }
883     else {
884         /* Oops, OOM. Put the callbacks back in the dict so
885          * we'll have another go if/when the user frees some memory
886          * and tries calling this method again. */
887         PyDict_SetItem(self->object_paths, path, callbacks);
888         /* END PARANOIA on failing code path */
889         /* If the SetItem failed, there's nothing we can do about it - but
890         since we know it's an existing entry, it shouldn't be able to fail
891         anyway. */
892         Py_DECREF(path);
893         Py_DECREF(callbacks);
894         return PyErr_NoMemory();
895     }
898     /* dbus_connection_get_object_path_data - not useful to Python,
899      * the object path data is just a PyString containing the path */
900     /* dbus_connection_list_registered could be useful, though */
902 /* dbus_connection_set_change_sigpipe - sets global state */
904 /* Maxima. Does Python code ever need to manipulate these?
905  * OTOH they're easy to wrap */
906     /* dbus_connection_set_max_message_size */
907     /* dbus_connection_get_max_message_size */
908     /* dbus_connection_set_max_received_size */
909     /* dbus_connection_get_max_received_size */
911 /* dbus_connection_get_outgoing_size - almost certainly unneeded */
913 struct PyMethodDef DBusPyConnection_tp_methods[] = {
914 #define ENTRY(name, flags) {#name, (PyCFunction)Connection_##name, flags, Connection_##name##__doc__}
915     ENTRY(_require_main_loop, METH_NOARGS),
916     ENTRY(close, METH_NOARGS),
917     ENTRY(flush, METH_NOARGS),
918     ENTRY(get_is_connected, METH_NOARGS),
919     ENTRY(get_is_authenticated, METH_NOARGS),
920     ENTRY(set_exit_on_disconnect, METH_VARARGS),
921     ENTRY(get_unix_fd, METH_NOARGS),
922     ENTRY(get_peer_unix_user, METH_NOARGS),
923     ENTRY(get_peer_unix_process_id, METH_NOARGS),
924     ENTRY(add_message_filter, METH_O),
925     ENTRY(_register_object_path, METH_VARARGS|METH_KEYWORDS),
926     ENTRY(remove_message_filter, METH_O),
927     ENTRY(send_message, METH_VARARGS),
928     ENTRY(send_message_with_reply, METH_VARARGS|METH_KEYWORDS),
929     ENTRY(send_message_with_reply_and_block, METH_VARARGS),
930     ENTRY(_unregister_object_path, METH_VARARGS|METH_KEYWORDS),
931     {NULL},
932 #undef ENTRY
935 /* vim:set ft=c cino< sw=4 sts=4 et: */