more robust and unicode safe dbus string handling
[dbuscron] / dbuscron / bus.py
1
2 import dbus
3
4 from dbuscron.logger import Logger
5 log = Logger(__name__)
6
7 def dbus_to_str(value):
8     try:
9         if isinstance(value, dbus.Byte):
10             result = str(int(value))
11         elif isinstance(value, dbus.ByteArray):
12             result = ','.join(str(ord(v)) for v in value)
13         elif isinstance(value, dbus.Array):
14             result = ','.join(dbus_to_str(v) for v in value)
15         elif isinstance(value, dbus.Dictionary):
16             result = ','.join('%s:%s' % (k, dbus_to_str(v)) for k, v in value.iteritems())
17         elif isinstance(value, dbus.String):
18             result = value.encode('utf-8')
19         else:
20             result = str(value)
21         return result
22     except Exception, e:
23         log.error('convert exception', e)
24         raise e
25
26
27 def get_dbus_message_type(message):
28     result = message.__class__.__name__[0:-7]
29     for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
30         result = result.replace(c, '_'+c.lower())
31     return result.strip('_')
32
33 class DbusBus(object):
34     __bus = None
35     __system_bus = None
36     __session_bus = None
37
38     def __new__(cls):
39         if not cls.__bus:
40             cls.__bus = super(DbusBus, cls).__new__(cls)
41         return cls.__bus
42
43     def __init__(self):
44         from dbus.mainloop.glib import DBusGMainLoop
45         DBusGMainLoop(set_as_default=True)
46
47     @property
48     def system(self):
49         if not self.__system_bus:
50             self.__system_bus = dbus.SystemBus()
51         return self.__system_bus
52
53     @property
54     def session(self):
55         if not self.__session_bus:
56             self.__session_bus = dbus.SessionBus()
57         return self.__session_bus
58
59     def attach_handler(self, handler):
60         if self.__system_bus:
61             self.__system_bus.add_message_filter(handler)
62         if self.__session_bus:
63             self.__session_bus.add_message_filter(handler)
64     def listen(self):
65         from gobject import MainLoop
66         loop = MainLoop()
67         loop.run()
68
69 class DbusRule(object):
70     def __init__(self, bus_=None, type_=None, sender_=None, interface_=None, path_=None, member_=None, destination_=None, args_=[]):
71         self._bus         = bus_
72         self._type        = type_
73         self._sender      = sender_
74         self._interface   = interface_
75         self._path        = path_
76         self._member      = member_
77         self._destination = destination_
78         self._args        = args_
79
80     def register(self):
81         rule = str(self)
82         if rule:
83             self._bus.add_match_string(rule)
84
85     def unregister(self):
86         rule = str(self)
87         if rule:
88             self._bus.remove_match_string(rule)
89
90     def __del__(self):
91        self.unregister()
92
93     def __str__(self):
94         rule = []
95         for key in ['type', 'sender', 'interface', 'path', 'member', 'destination']:
96             value = getattr(self, '_'+key)
97             if value is not None:
98                 rule.append("%s='%s'" % (key, value))
99
100         if self._args:
101             for i, arg in enumerate(self._args):
102                 rule.append("arg%d%s='%s'" % (i, 'path' if arg.startswith('/') else '', arg))
103
104         return ','.join(rule)
105
106     def match(self, bus, message):
107
108         if self._bus not in (None, bus):
109             return False
110
111         if self._type is not None:
112             type_ = get_dbus_message_type(message)
113             if self._type != type_:
114                 return False
115
116         if self._sender not in (None, message.get_sender()):
117             return False
118
119         if self._interface not in (None, message.get_interface()):
120             return False
121
122         if self._path not in (None, message.get_path()):
123             return False
124
125         if self._member not in (None, message.get_member()):
126             return False
127
128         if self._destination not in (None, message.get_destination()):
129             return False
130
131         if self._args is not None:
132             args_ = message.get_args_list()
133             for i, arg in enumerate(args_):
134                 if i >= len(self._args):
135                     break
136                 if self._args[i] not in (None, str(arg)):
137                     return False
138
139         return True
140