3 #include "dbus_h_wrapper.h"
5 cdef extern from "stdlib.h":
6 cdef void *malloc(size_t size)
7 cdef void free(void *ptr)
9 cdef extern from "dbus-glib.h":
10 ctypedef struct GMainContext
11 cdef void dbus_connection_setup_with_g_main (DBusConnection *connection,
12 GMainContext *context)
13 cdef void dbus_server_setup_with_g_main (DBusServer *server,
14 GMainContext *context)
16 cdef extern from "Python.h":
17 void Py_XINCREF (object)
18 void Py_XDECREF (object)
21 ctypedef struct DBusError:
31 ctypedef struct DBusMessageIter:
47 ctypedef struct DBusObjectPathVTable:
48 DBusObjectPathUnregisterFunction unregister_function
49 DBusObjectPathMessageFunction message_function
50 void (* dbus_internal_pad1) (void *)
51 void (* dbus_internal_pad2) (void *)
52 void (* dbus_internal_pad3) (void *)
53 void (* dbus_internal_pad4) (void *)
56 _user_data_references = [ ]
58 class DBusException(Exception):
61 class ConnectionError(Exception):
64 cdef void cunregister_function_handler (DBusConnection *connection,
66 tup = <object>user_data
67 assert (type(tup) == list)
69 args = [Connection(_conn=<object>connection)]
72 cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection,
75 tup = <object>user_data
76 assert (type(tup) == list)
78 message = Message(_create=0)
79 message._set_msg(<object>msg)
80 args = [Connection(_conn=<object>connection),
82 retval = function(*args)
84 retval = DBUS_HANDLER_RESULT_HANDLED
87 cdef class Connection:
88 cdef DBusConnection *conn
90 # FIXME: this is a major major hack. We use this because casting values to
91 # python objects and returning seemed to be corrupting them. This is a "global variable" :-(
92 cdef char **_parsed_path
94 def __init__(self, address=None, _conn=None):
96 dbus_error_init(&error)
97 if <DBusConnection*>_conn != NULL:
98 self.conn = <DBusConnection*>_conn
99 dbus_connection_ref(self.conn)
101 self.conn = dbus_connection_open(address,
103 if dbus_error_is_set(&error):
104 raise DBusException, error.message
106 dbus_connection_ref(self.conn)
108 def _set_conn(self, conn):
109 self.conn = <DBusConnection*>conn
112 return <object>self.conn
114 #FIXME: this is totally busted, don't use a class shared member like parsed_path
115 def _build_parsed_path(self, path_element_list):
116 cdef char **cpatharray
117 size = len(path_element_list)
118 cpatharray = <char **>malloc(sizeof(char*) * (size + 1))
120 for i in range(size):
121 path_element = path_element_list[i]
122 cpatharray[i] = path_element
124 cpatharray[size] = NULL
126 self._parsed_path = cpatharray
128 def get_base_service(self):
129 return bus_get_base_service(self)
131 def setup_with_g_main(self):
132 dbus_connection_setup_with_g_main(self.conn, NULL)
134 def disconnect(self):
135 dbus_connection_disconnect(self.conn)
137 def get_is_connected(self):
138 return dbus_connection_get_is_connected(self.conn)
140 def get_is_authenticated(self):
141 return dbus_connection_get_is_authenticated(self.conn)
144 dbus_connection_flush(self.conn)
146 def borrow_message(self):
147 m = Message(_create=0)
148 m._set_msg(<object>dbus_connection_borrow_message(self.conn))
151 def return_message(self, message):
152 msg = message._get_msg()
153 dbus_connection_return_message(self.conn, <DBusMessage*>msg)
155 def steal_borrowed_message(self, message):
156 msg = message._get_msg()
157 dbus_connection_steal_borrowed_message(self.conn,
160 def pop_message(self):
161 cdef DBusMessage *msg
162 msg = dbus_connection_pop_message(self.conn)
164 m = Message(_create=0)
165 m._set_msg(<object>msg)
170 def get_dispatch_status(self):
171 return dbus_connection_get_dispatch_status(self.conn)
174 return dbus_connection_dispatch(self.conn)
176 def send(self, message):
177 #cdef dbus_uint32_t client_serial
178 #if type(message) != Message:
181 msg = message._get_msg()
182 retval = dbus_connection_send(self.conn,
187 def send_with_reply(self, message, timeout_milliseconds):
188 cdef dbus_bool_t retval
189 cdef DBusPendingCall *cpending_call
191 dbus_error_init(&error)
195 msg = message._get_msg()
197 retval = dbus_connection_send_with_reply(self.conn,
200 timeout_milliseconds)
202 if dbus_error_is_set(&error):
203 raise DBusException, error.message
205 if (cpending_call != NULL):
206 pending_call = PendingCall(<object>cpending_call)
210 return (retval, pending_call)
212 def send_with_reply_and_block(self, message,
213 timeout_milliseconds=0):
214 cdef DBusMessage * retval
216 dbus_error_init(&error)
218 msg = message._get_msg()
220 retval = dbus_connection_send_with_reply_and_block(
221 <DBusConnection*>self.conn,
223 <int>timeout_milliseconds,
226 if dbus_error_is_set(&error):
227 raise DBusException, error.message
232 m = Message(_create=0)
233 m._set_msg(<object>retval)
236 def set_watch_functions(self, add_function, remove_function, data):
239 def set_timeout_functions(self, add_function, remove_function, data):
242 def set_wakeup_main_function(self, wakeup_main_function, data):
245 # FIXME: set_dispatch_status_function, get_unix_user, set_unix_user_function
247 def add_filter(self, filter_function):
248 user_data = [ filter_function ]
249 global _user_data_references
250 _user_data_references.append(user_data)
252 return dbus_connection_add_filter(self.conn,
253 cmessage_function_handler,
258 #FIXME: remove_filter
259 # this is pretty tricky, we want to only remove the filter
260 # if we truly have no more calls to our message_function_handler...ugh
262 def set_data(self, slot, data):
265 def get_data(self, slot):
268 def set_max_message_size(self, size):
269 dbus_connection_set_max_message_size(self.conn, size)
271 def get_max_message_size(self):
272 return dbus_connection_get_max_message_size(self.conn)
274 def set_max_received_size(self, size):
275 dbus_connection_set_max_received_size(self.conn, size)
277 def get_max_received_size(self):
278 return dbus_connection_get_max_received_size(self.conn)
280 def get_outgoing_size(self):
281 return dbus_connection_get_outgoing_size(self.conn)
283 # preallocate_send, free_preallocated_send, send_preallocated
285 def register_object_path(self, path, unregister_cb, message_cb):
286 cdef DBusObjectPathVTable cvtable
288 cvtable.unregister_function = cunregister_function_handler
289 cvtable.message_function = cmessage_function_handler
291 user_data = [message_cb, unregister_cb]
292 global _user_data_references
293 _user_data_references.append(user_data)
295 path_element_list = path[1:].split('/')
296 self._build_parsed_path(path_element_list)
298 return dbus_connection_register_object_path(self.conn, self._parsed_path, &cvtable,
301 def register_fallback(self, path, unregister_cb, message_cb):
302 cdef DBusObjectPathVTable cvtable
304 cvtable.unregister_function = cunregister_function_handler
305 cvtable.message_function = cmessage_function_handler
307 user_data = [message_cb, unregister_cb]
308 global _user_data_references
309 _user_data_references.append(user_data)
311 path_element_list = path[1:].split('/')
312 self._build_parsed_path(path_element_list)
314 return dbus_connection_register_fallback(self.conn, self._parsed_path, &cvtable,
317 #FIXME: unregister_object_path , see problems with remove_filter
319 def list_registered (self, parent_path):
320 cdef char **cchild_entries
321 cdef dbus_bool_t retval
323 path_element_list = parent_path[1:].split('/')
324 self._build_parsed_path(path_element_list)
326 retval = dbus_connection_list_registered(self.conn, self._parsed_path, &cchild_entries)
329 #FIXME: raise out of memory exception?
335 while (cchild_entries[i] != NULL):
336 child_entries.append(cchild_entries[i])
339 dbus_free_string_array(cchild_entries)
344 cdef class PendingCall:
345 cdef DBusPendingCall *pending_call
347 def __init__(self, _pending_call):
348 self.pending_call = <DBusPendingCall*>_pending_call
349 dbus_pending_call_ref(self.pending_call)
351 def _get_pending_call(self):
352 return <object>self.pending_call
355 dbus_pending_call_cancel(self.pending_call)
357 def get_completed(self):
358 return dbus_pending_call_get_completed(self.pending_call)
361 message = Message(_create=0)
362 message._set_msg(<object>dbus_pending_call_get_reply(self.pending_call))
366 dbus_pending_call_block(self.pending_call)
369 cdef DBusWatch* watch
370 def __init__(self, cwatch):
371 self.watch = <DBusWatch*>cwatch
374 return dbus_watch_get_fd(self.watch)
376 # FIXME: not picked up correctly by extract.py
377 #def get_flags(self):
378 # return dbus_watch_get_flags(self.watch)
380 def handle(self, flags):
381 return dbus_watch_handle(self.watch, flags)
383 def get_enabled(self):
384 return dbus_watch_get_enabled(self.watch)
386 cdef class MessageIter:
387 cdef DBusMessageIter *iter
388 cdef DBusMessageIter real_iter
391 def __init__(self, message):
392 self.iter = &self.real_iter
393 msg = message._get_msg()
394 dbus_message_iter_init(<DBusMessage*>msg, self.iter)
397 return <object>self.iter
400 return dbus_message_iter_has_next(self.iter)
403 return dbus_message_iter_next(self.iter)
406 arg_type = self.get_arg_type()
408 if arg_type == TYPE_INVALID:
409 raise TypeError, 'Invalid arg type in MessageIter'
410 elif arg_type == TYPE_STRING:
411 retval = self.get_string()
412 elif arg_type == TYPE_INT32:
413 retval = self.get_int32()
414 elif arg_type == TYPE_UINT32:
415 retval = self.get_uint32()
416 elif arg_type == TYPE_DOUBLE:
417 retval = self.get_double()
418 elif arg_type == TYPE_BYTE:
419 retval = self.get_byte()
420 elif arg_type == TYPE_BOOLEAN:
421 retval = self.get_boolean()
422 elif arg_type == TYPE_ARRAY:
423 array_type = self.get_array_type()
425 if array_type == TYPE_STRING:
426 retval = self.get_string_array()
427 elif array_type == TYPE_BOOLEAN:
428 retval = self.get_boolean_array()
430 raise TypeError, "Unknown array type %d in MessageIter" % (array_type)
431 elif arg_type == TYPE_DICT:
432 retval = self.get_dict()
434 raise TypeError, 'Unknown arg type %d in MessageIter' % (arg_type)
439 cdef DBusMessageIter dict_iter
440 cdef DBusMessageIter* old_iter
443 dbus_message_iter_init_dict_iterator(self.iter, &dict_iter)
444 # FIXME: nasty hack so we can use existing self.get() method
446 self.iter = &dict_iter
449 key = self.get_dict_key()
452 if not self.has_next():
459 def get_arg_type(self):
460 return dbus_message_iter_get_arg_type(self.iter)
462 def get_array_type(self):
463 return dbus_message_iter_get_array_type(self.iter)
465 #FIXME: implement get_byte
467 # return dbus_message_iter_get_byte(self.iter)
469 def get_boolean(self):
470 return dbus_message_iter_get_boolean(self.iter)
473 return dbus_message_iter_get_int32(self.iter)
475 def get_uint32(self):
476 return dbus_message_iter_get_uint32(self.iter)
478 def get_double(self):
479 return dbus_message_iter_get_double(self.iter)
481 def get_string(self):
482 return dbus_message_iter_get_string(self.iter)
484 def get_dict_key(self):
485 return dbus_message_iter_get_dict_key(self.iter)
487 # FIXME: implement dbus_message_iter_get_named
488 # dbus_message_iter_init_array_iterator
490 def get_byte_array(self):
492 cdef unsigned char *retval
493 dbus_message_iter_get_byte_array(self.iter, &retval, <int*>&len)
495 for i from 0 <= i < len:
496 list.append(chr(retval[i]))
499 # FIXME: implement dbus_message_iter_get_boolean_array
500 # dbus_message_iter_get_int32_array
501 # dbus_message_iter_get_uint32_array
502 # dbus_message_iter_get_double_array
504 def get_string_array(self):
508 dbus_message_iter_get_string_array(self.iter, &retval, <int*>&len)
510 for i from 0 <= i < len:
511 list.append(retval[i])
514 # dbus_message_append_iter_init included in class Message
516 #FIXME: handle all the different types?
517 def append(self, value):
518 value_type = type(value)
520 if value_type == bool:
521 retval = self.append_boolean(value)
522 elif value_type == int:
523 retval = self.append_int32(value)
524 elif value_type == float:
525 retval = self.append_double(value)
526 elif value_type == str:
527 retval = self.append_string(value)
528 elif value_type == list:
530 raise TypeError, "Empty list"
531 list_type = type(list[0])
533 self.append_string_array(list)
535 raise TypeError, "List of unknown type '%s'" % (list_type)
537 raise TypeError, "Argument of unknown type '%s'" % (value_type)
541 def append_nil(self):
542 return dbus_message_iter_append_nil(self.iter)
544 def append_boolean(self, value):
545 return dbus_message_iter_append_boolean(self.iter, value)
547 def append_byte(self, value):
548 return dbus_message_iter_append_byte(self.iter, value)
550 def append_int32(self, value):
551 return dbus_message_iter_append_int32(self.iter, value)
553 def append_uint32(self, value):
554 return dbus_message_iter_append_uint32(self.iter, value)
556 def append_double(self, value):
557 return dbus_message_iter_append_double(self.iter, value)
559 def append_string(self, value):
560 return dbus_message_iter_append_string(self.iter, value)
562 # FIXME: dbus_message_iter_append_named
564 def append_dict_key(self, value):
565 return dbus_message_iter_append_dict_key(self.iter, value)
567 # FIXME: append_array, append_dict_array, append_boolean_array, append_int32_array, append_uint32_array, append_double_array
569 def append_byte_array(self, list):
570 cdef unsigned char * value
573 value = <unsigned char*>malloc(length)
574 for i from 0 <= i < length:
576 if type(item) != str or len(item) != 1:
579 return dbus_message_iter_append_byte_array(self.iter, value, length)
581 def append_string_array(self, list):
585 value = <char**>malloc(length)
586 for i from 0 <= i < length:
588 if type(item) != str:
591 return dbus_message_iter_append_string_array(self.iter, value, length)
594 (MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5)
595 (TYPE_INVALID, TYPE_NIL, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_CUSTOM, TYPE_ARRAY, TYPE_DICT, TYPE_OBJECT_PATH) = (0, ord('v'), ord('y'), ord('b'), ord('i'), ord('u'), ord('x'), ord('t'), ord('d'), ord('s'), ord('c'), ord('a'), ord('m'), ord('o'))
598 cdef DBusMessage *msg
600 def __init__(self, message_type=MESSAGE_TYPE_INVALID,
601 service=None, path=None, interface=None, method=None,
604 reply_to=None, error_name=None, error_message=None,
607 if (service == None):
615 if message_type == MESSAGE_TYPE_METHOD_CALL:
616 self.msg = dbus_message_new_method_call(cservice, path, interface, method)
617 elif message_type == MESSAGE_TYPE_METHOD_RETURN:
618 cmsg = method_call._get_msg()
619 self.msg = dbus_message_new_method_return(<DBusMessage*>cmsg)
620 elif message_type == MESSAGE_TYPE_SIGNAL:
621 self.msg = dbus_message_new_signal(path, interface, name)
622 elif message_type == MESSAGE_TYPE_ERROR:
623 cmsg = reply_to._get_msg()
624 self.msg = dbus_message_new_error(<DBusMessage*>cmsg, error_name, error_message)
626 def type_to_name(self, type):
627 if type == MESSAGE_TYPE_SIGNAL:
629 elif type == MESSAGE_TYPE_METHOD_CALL:
631 elif type == MESSAGE_TYPE_METHOD_RETURN:
632 return "method return"
633 elif type == MESSAGE_TYPE_ERROR:
636 return "(unknown message type)"
639 message_type = self.get_type()
640 sender = self.get_sender()
643 sender = "(no sender)"
645 if (message_type == MESSAGE_TYPE_METHOD_CALL) or (message_type == MESSAGE_TYPE_SIGNAL):
646 retval = '%s interface=%s; member=%s; sender=%s' % (self.type_to_name(message_type),
647 self.get_interface(),
650 elif message_type == MESSAGE_TYPE_METHOD_RETURN:
651 retval = '%s sender=%s' % (self.type_to_name(message_type),
653 elif message_type == MESSAGE_TYPE_ERROR:
654 retval = '%s name=%s; sender=%s' % (self.type_to_name(message_type),
655 self.get_error_name(),
658 retval = "Message of unknown type %d" % (message_type)
661 # FIXME: should really use self.convert_to_tuple() here
663 iter = self.get_iter()
666 while (value_at_iter):
667 type = iter.get_arg_type()
669 if type == TYPE_INVALID:
671 elif type == TYPE_STRING:
672 str = iter.get_string()
673 arg = 'string:%s\n' % (str)
674 elif type == TYPE_INT32:
675 num = iter.get_int32()
676 arg = 'int32:%d\n' % (num)
677 elif type == TYPE_UINT32:
678 num = iter.get_uint32()
679 arg = 'uint32:%u\n' % (num)
680 elif type == TYPE_DOUBLE:
681 num = iter.get_double()
682 arg = 'double:%f\n' % (num)
683 elif type == TYPE_BYTE:
684 num = iter.get_byte()
685 arg = 'byte:%d\n' % (num)
686 elif type == TYPE_BOOLEAN:
687 bool = iter.get_boolean()
692 arg = 'boolean:%s\n' % (str)
694 arg = '(unknown arg type %d)\n' % type
696 retval = retval + arg
697 value_at_iter = iter.next()
701 def _set_msg(self, msg):
702 self.msg = <DBusMessage*>msg
705 return <object>self.msg
708 return MessageIter(self)
710 def get_args_list(self):
713 iter = self.get_iter()
715 retval.append(iter.get())
719 value_at_iter = iter.next()
720 while (value_at_iter):
721 retval.append(iter.get())
722 value_at_iter = iter.next()
726 # FIXME: implement dbus_message_copy?
729 return dbus_message_get_type(self.msg)
731 def set_path(self, object_path):
732 return dbus_message_set_path(self.msg, object_path)
735 return dbus_message_get_path(self.msg)
737 def set_interface(self, interface):
738 return dbus_message_set_interface(self.msg, interface)
740 def get_interface(self):
741 return dbus_message_get_interface(self.msg)
743 def set_member(self, member):
744 return dbus_message_set_member(self.msg, member)
746 def get_member(self):
747 return dbus_message_get_member(self.msg)
749 def set_error_name(self, name):
750 return dbus_message_set_error_name(self.msg, name)
752 def get_error_name(self):
753 return dbus_message_get_error_name(self.msg)
755 def set_destination(self, destination):
756 return dbus_message_set_destination(self.msg, destination)
758 def get_destination(self):
759 return dbus_message_get_destination(self.msg)
761 def set_sender(self, sender):
762 return dbus_message_set_sender(self.msg, sender)
764 def get_sender(self):
766 sender = dbus_message_get_sender(self.msg)
772 def set_no_reply(self, no_reply):
773 dbus_message_set_no_reply(self.msg, no_reply)
775 def get_no_reply(self):
776 return dbus_message_get_no_reply(self.msg)
778 def is_method_call(self, interface, method):
779 return dbus_message_is_method_call(self.msg, interface, method)
781 def is_signal(self, interface, signal_name):
782 return dbus_message_is_signal(self.msg, interface, signal_name)
784 def is_error(self, error_name):
785 return dbus_message_is_error(self.msg, error_name)
787 def has_destination(self, service):
788 return dbus_message_has_destination(self.msg, service)
790 def has_sender(self, service):
791 return dbus_message_has_sender(self.msg, service)
793 def get_serial(self):
794 return dbus_message_get_serial(self.msg)
796 def set_reply_serial(self, reply_serial):
797 return dbus_message_set_reply_serial(self.msg, reply_serial)
799 def get_reply_serial(self):
800 return dbus_message_get_reply_serial(self.msg)
802 #FIXME: dbus_message_get_path_decomposed
804 # FIXME: all the different dbus_message_*args* methods
806 class Signal(Message):
807 def __init__(self, spath, sinterface, sname):
808 Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, interface=sinterface, name=sname)
810 class MethodCall(Message):
811 def __init__(self, mpath, minterface, mmethod):
812 Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod)
814 class MethodReturn(Message):
815 def __init__(self, method_call):
816 Message.__init__(self, MESSAGE_TYPE_METHOD_RETURN, method_call=method_call)
818 class Error(Message):
819 def __init__(self, reply_to, error_name, error_message):
820 Message.__init__(self, MESSAGE_TYPE_ERROR, reply_to=reply_to, error_name=error_name, error_message=error_message)
823 cdef DBusServer *server
824 def __init__(self, address):
826 dbus_error_init(&error)
827 self.server = dbus_server_listen(address,
829 if dbus_error_is_set(&error):
830 raise DBusException, error.message
832 def setup_with_g_main (self):
833 dbus_server_setup_with_g_main(self.server, NULL)
835 def disconnect(self):
836 dbus_server_disconnect(self.server)
838 def get_is_connected(self):
839 return dbus_server_get_is_connected(self.server)
841 # def set_new_connection_function(self, function, data):
842 # dbus_server_set_new_connection_function(self.conn, function,
845 # def set_watch_functions(self, add_function, remove_function, data):
846 # dbus_server_set_watch_functions(self.server,
847 # add_function, remove_function,
850 # def set_timeout_functions(self, add_function, remove_function, data):
851 # dbus_server_set_timeout_functions(self.server,
852 # add_function, remove_function,
855 # def handle_watch(self, watch, condition):
856 # dbus_server_handle_watch(self.conn, watch, condition)
858 BUS_SESSION = DBUS_BUS_SESSION
859 BUS_SYSTEM = DBUS_BUS_SYSTEM
860 BUS_ACTIVATION = DBUS_BUS_ACTIVATION
862 def bus_get (bus_type):
864 dbus_error_init(&error)
865 cdef DBusConnection *connection
867 connection = dbus_bus_get(bus_type,
870 if dbus_error_is_set(&error):
871 raise DBusException, error.message
873 return Connection(_conn=<object>connection)
875 def bus_get_base_service(connection):
876 conn = connection._get_conn()
877 return dbus_bus_get_base_service(<DBusConnection*>conn)
879 def bus_register(connection):
881 dbus_error_init(&error)
882 cdef dbus_bool_t retval
884 conn = connection._get_conn()
885 retval = dbus_bus_register(<DBusConnection*>conn,
887 if dbus_error_is_set(&error):
888 raise DBusException, error.message
892 SERVICE_FLAG_PROHIBIT_REPLACEMENT = 0x1
893 SERVICE_FLAG_REPLACE_EXISTING = 0x2
895 def bus_acquire_service(connection, service_name, flags=0):
897 dbus_error_init(&error)
900 conn = connection._get_conn()
901 retval = dbus_bus_acquire_service(<DBusConnection*>conn,
905 if dbus_error_is_set(&error):
906 raise DBusException, error.message
909 def bus_service_exists(connection, service_name):
911 dbus_error_init(&error)
912 cdef dbus_bool_t retval
914 conn = connection._get_conn()
915 retval = dbus_bus_service_exists(<DBusConnection*>conn,
918 if dbus_error_is_set(&error):
919 raise DBusException, error.message
922 def bus_add_match(connection, rule):
924 dbus_error_init(&error)
926 conn = connection._get_conn()
927 dbus_bus_add_match (<DBusConnection*>conn, rule, &error)
929 if dbus_error_is_set(&error):
930 raise DBusException, error.message
932 def bus_remove_match(connection, rule):
934 dbus_error_init(&error)
936 conn = connection._get_conn()
937 dbus_bus_remove_match (<DBusConnection*>conn, rule, &error)
939 if dbus_error_is_set(&error):
940 raise DBusException, error.message