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)
432 raise TypeError, 'Unknown arg type %d in MessageIter' % (argtype)
436 def get_arg_type(self):
437 return dbus_message_iter_get_arg_type(self.iter)
439 def get_array_type(self):
440 return dbus_message_iter_get_array_type(self.iter)
442 #FIXME: implement get_byte
444 # return dbus_message_iter_get_byte(self.iter)
446 def get_boolean(self):
447 return dbus_message_iter_get_boolean(self.iter)
450 return dbus_message_iter_get_int32(self.iter)
452 def get_uint32(self):
453 return dbus_message_iter_get_uint32(self.iter)
455 def get_double(self):
456 return dbus_message_iter_get_double(self.iter)
458 def get_string(self):
459 return dbus_message_iter_get_string(self.iter)
461 def get_dict_key(self):
462 return dbus_message_iter_get_dict_key(self.iter)
464 # FIXME: implement dbus_message_iter_get_named
465 # dbus_message_iter_init_array_iterator
467 def get_byte_array(self):
469 cdef unsigned char *retval
470 dbus_message_iter_get_byte_array(self.iter, &retval, <int*>&len)
472 for i from 0 <= i < len:
473 list.append(chr(retval[i]))
476 # FIXME: implement dbus_message_iter_get_boolean_array
477 # dbus_message_iter_get_int32_array
478 # dbus_message_iter_get_uint32_array
479 # dbus_message_iter_get_double_array
481 def get_string_array(self):
485 dbus_message_iter_get_string_array(self.iter, &retval, <int*>&len)
487 for i from 0 <= i < len:
488 list.append(retval[i])
491 # dbus_message_append_iter_init included in class Message
493 #FIXME: handle all the different types?
494 def append(self, value):
495 value_type = type(value)
497 if value_type == bool:
498 retval = self.append_boolean(value)
499 elif value_type == int:
500 retval = self.append_int32(value)
501 elif value_type == float:
502 retval = self.append_double(value)
503 elif value_type == str:
504 retval = self.append_string(value)
505 elif value_type == list:
507 raise TypeError, "Empty list"
508 list_type = type(list[0])
510 self.append_string_array(list)
512 raise TypeError, "List of unknown type '%s'" % (list_type)
514 raise TypeError, "Argument of unknown type '%s'" % (value_type)
518 def append_nil(self):
519 return dbus_message_iter_append_nil(self.iter)
521 def append_boolean(self, value):
522 return dbus_message_iter_append_boolean(self.iter, value)
524 def append_byte(self, value):
525 return dbus_message_iter_append_byte(self.iter, value)
527 def append_int32(self, value):
528 return dbus_message_iter_append_int32(self.iter, value)
530 def append_uint32(self, value):
531 return dbus_message_iter_append_uint32(self.iter, value)
533 def append_double(self, value):
534 return dbus_message_iter_append_double(self.iter, value)
536 def append_string(self, value):
537 return dbus_message_iter_append_string(self.iter, value)
539 # FIXME: dbus_message_iter_append_named
541 def append_dict_key(self, value):
542 return dbus_message_iter_append_dict_key(self.iter, value)
544 # FIXME: append_array, append_dict_array, append_boolean_array, append_int32_array, append_uint32_array, append_double_array
546 def append_byte_array(self, list):
547 cdef unsigned char * value
550 value = <unsigned char*>malloc(length)
551 for i from 0 <= i < length:
553 if type(item) != str or len(item) != 1:
556 return dbus_message_iter_append_byte_array(self.iter, value, length)
558 def append_string_array(self, list):
562 value = <char**>malloc(length)
563 for i from 0 <= i < length:
565 if type(item) != str:
568 return dbus_message_iter_append_string_array(self.iter, value, length)
571 (MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5)
572 (TYPE_INVALID, TYPE_NIL, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_NAMED, TYPE_ARRAY, TYPE_DICT, TYPE_OBJECT_PATH) = range(14)
575 cdef DBusMessage *msg
577 def __init__(self, message_type=MESSAGE_TYPE_INVALID,
578 service=None, path=None, interface=None, method=None,
581 reply_to=None, error_name=None, error_message=None,
584 if (service == None):
592 if message_type == MESSAGE_TYPE_METHOD_CALL:
593 self.msg = dbus_message_new_method_call(cservice, path, interface, method)
594 elif message_type == MESSAGE_TYPE_METHOD_RETURN:
595 cmsg = method_call._get_msg()
596 self.msg = dbus_message_new_method_return(<DBusMessage*>cmsg)
597 elif message_type == MESSAGE_TYPE_SIGNAL:
598 self.msg = dbus_message_new_signal(path, interface, name)
599 elif message_type == MESSAGE_TYPE_ERROR:
600 cmsg = reply_to._get_msg()
601 self.msg = dbus_message_new_error(<DBusMessage*>cmsg, error_name, error_message)
603 def type_to_name(self, type):
604 if type == MESSAGE_TYPE_SIGNAL:
606 elif type == MESSAGE_TYPE_METHOD_CALL:
608 elif type == MESSAGE_TYPE_METHOD_RETURN:
609 return "method return"
610 elif type == MESSAGE_TYPE_ERROR:
613 return "(unknown message type)"
616 message_type = self.get_type()
617 sender = self.get_sender()
620 sender = "(no sender)"
622 if (message_type == MESSAGE_TYPE_METHOD_CALL) or (message_type == MESSAGE_TYPE_SIGNAL):
623 retval = '%s interface=%s; member=%s; sender=%s' % (self.type_to_name(message_type),
624 self.get_interface(),
627 elif message_type == MESSAGE_TYPE_METHOD_RETURN:
628 retval = '%s sender=%s' % (self.type_to_name(message_type),
630 elif message_type == MESSAGE_TYPE_ERROR:
631 retval = '%s name=%s; sender=%s' % (self.type_to_name(message_type),
632 self.get_error_name(),
635 retval = "Message of unknown type %d" % (message_type)
638 # FIXME: should really use self.convert_to_tuple() here
640 iter = self.get_iter()
643 while (value_at_iter):
644 type = iter.get_arg_type()
646 if type == TYPE_INVALID:
648 elif type == TYPE_STRING:
649 str = iter.get_string()
650 arg = 'string:%s\n' % (str)
651 elif type == TYPE_INT32:
652 num = iter.get_int32()
653 arg = 'int32:%d\n' % (num)
654 elif type == TYPE_UINT32:
655 num = iter.get_uint32()
656 arg = 'uint32:%u\n' % (num)
657 elif type == TYPE_DOUBLE:
658 num = iter.get_double()
659 arg = 'double:%f\n' % (num)
660 elif type == TYPE_BYTE:
661 num = iter.get_byte()
662 arg = 'byte:%d\n' % (num)
663 elif type == TYPE_BOOLEAN:
664 bool = iter.get_boolean()
669 arg = 'boolean:%s\n' % (str)
671 arg = '(unknown arg type %d)\n' % type
673 retval = retval + arg
674 value_at_iter = iter.next()
678 def _set_msg(self, msg):
679 self.msg = <DBusMessage*>msg
682 return <object>self.msg
685 return MessageIter(self)
687 def get_args_list(self):
690 iter = self.get_iter()
692 retval.append(iter.get())
696 value_at_iter = iter.next()
697 while (value_at_iter):
698 retval.append(iter.get())
699 value_at_iter = iter.next()
703 # FIXME: implement dbus_message_copy?
706 return dbus_message_get_type(self.msg)
708 def set_path(self, object_path):
709 return dbus_message_set_path(self.msg, object_path)
712 return dbus_message_get_path(self.msg)
714 def set_interface(self, interface):
715 return dbus_message_set_interface(self.msg, interface)
717 def get_interface(self):
718 return dbus_message_get_interface(self.msg)
720 def set_member(self, member):
721 return dbus_message_set_member(self.msg, member)
723 def get_member(self):
724 return dbus_message_get_member(self.msg)
726 def set_error_name(self, name):
727 return dbus_message_set_error_name(self.msg, name)
729 def get_error_name(self):
730 return dbus_message_get_error_name(self.msg)
732 def set_destination(self, destination):
733 return dbus_message_set_destination(self.msg, destination)
735 def get_destination(self):
736 return dbus_message_get_destination(self.msg)
738 def set_sender(self, sender):
739 return dbus_message_set_sender(self.msg, sender)
741 def get_sender(self):
743 sender = dbus_message_get_sender(self.msg)
749 def set_no_reply(self, no_reply):
750 dbus_message_set_no_reply(self.msg, no_reply)
752 def get_no_reply(self):
753 return dbus_message_get_no_reply(self.msg)
755 def is_method_call(self, interface, method):
756 return dbus_message_is_method_call(self.msg, interface, method)
758 def is_signal(self, interface, signal_name):
759 return dbus_message_is_signal(self.msg, interface, signal_name)
761 def is_error(self, error_name):
762 return dbus_message_is_error(self.msg, error_name)
764 def has_destination(self, service):
765 return dbus_message_has_destination(self.msg, service)
767 def has_sender(self, service):
768 return dbus_message_has_sender(self.msg, service)
770 def get_serial(self):
771 return dbus_message_get_serial(self.msg)
773 def set_reply_serial(self, reply_serial):
774 return dbus_message_set_reply_serial(self.msg, reply_serial)
776 def get_reply_serial(self):
777 return dbus_message_get_reply_serial(self.msg)
779 #FIXME: dbus_message_get_path_decomposed
781 # FIXME: all the different dbus_message_*args* methods
783 class Signal(Message):
784 def __init__(self, spath, sinterface, sname):
785 Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, interface=sinterface, name=sname)
787 class MethodCall(Message):
788 def __init__(self, mpath, minterface, mmethod):
789 Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod)
791 class MethodReturn(Message):
792 def __init__(self, method_call):
793 Message.__init__(self, MESSAGE_TYPE_METHOD_RETURN, method_call=method_call)
795 class Error(Message):
796 def __init__(self, reply_to, error_name, error_message):
797 Message.__init__(self, MESSAGE_TYPE_ERROR, reply_to=reply_to, error_name=error_name, error_message=error_message)
800 cdef DBusServer *server
801 def __init__(self, address):
803 dbus_error_init(&error)
804 self.server = dbus_server_listen(address,
806 if dbus_error_is_set(&error):
807 raise DBusException, error.message
809 def setup_with_g_main (self):
810 dbus_server_setup_with_g_main(self.server, NULL)
812 def disconnect(self):
813 dbus_server_disconnect(self.server)
815 def get_is_connected(self):
816 return dbus_server_get_is_connected(self.server)
818 # def set_new_connection_function(self, function, data):
819 # dbus_server_set_new_connection_function(self.conn, function,
822 # def set_watch_functions(self, add_function, remove_function, data):
823 # dbus_server_set_watch_functions(self.server,
824 # add_function, remove_function,
827 # def set_timeout_functions(self, add_function, remove_function, data):
828 # dbus_server_set_timeout_functions(self.server,
829 # add_function, remove_function,
832 # def handle_watch(self, watch, condition):
833 # dbus_server_handle_watch(self.conn, watch, condition)
835 BUS_SESSION = DBUS_BUS_SESSION
836 BUS_SYSTEM = DBUS_BUS_SYSTEM
837 BUS_ACTIVATION = DBUS_BUS_ACTIVATION
839 def bus_get (bus_type):
841 dbus_error_init(&error)
842 cdef DBusConnection *connection
844 connection = dbus_bus_get(bus_type,
847 if dbus_error_is_set(&error):
848 raise DBusException, error.message
850 return Connection(_conn=<object>connection)
852 def bus_get_base_service(connection):
853 conn = connection._get_conn()
854 return dbus_bus_get_base_service(<DBusConnection*>conn)
856 def bus_register(connection):
858 dbus_error_init(&error)
859 cdef dbus_bool_t retval
861 conn = connection._get_conn()
862 retval = dbus_bus_register(<DBusConnection*>conn,
864 if dbus_error_is_set(&error):
865 raise DBusException, error.message
869 SERVICE_FLAG_PROHIBIT_REPLACEMENT = 0x1
870 SERVICE_FLAG_REPLACE_EXISTING = 0x2
872 def bus_acquire_service(connection, service_name, flags=0):
874 dbus_error_init(&error)
877 conn = connection._get_conn()
878 retval = dbus_bus_acquire_service(<DBusConnection*>conn,
882 if dbus_error_is_set(&error):
883 raise DBusException, error.message
886 def bus_service_exists(connection, service_name):
888 dbus_error_init(&error)
889 cdef dbus_bool_t retval
891 conn = connection._get_conn()
892 retval = dbus_bus_service_exists(<DBusConnection*>conn,
895 if dbus_error_is_set(&error):
896 raise DBusException, error.message
899 def bus_add_match(connection, rule):
901 dbus_error_init(&error)
903 conn = connection._get_conn()
904 dbus_bus_add_match (<DBusConnection*>conn, rule, &error)
906 if dbus_error_is_set(&error):
907 raise DBusException, error.message
909 def bus_remove_match(connection, rule):
911 dbus_error_init(&error)
913 conn = connection._get_conn()
914 dbus_bus_remove_match (<DBusConnection*>conn, rule, &error)
916 if dbus_error_is_set(&error):
917 raise DBusException, error.message