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