Unset DBUS_SESSION_BUS_ADDRESS to defend against stale environment
[dragbox.git] / Dragbox / dbuscontrol.py
blobb7f97368806f17e75f32bd8f8dd2c173c633ace9
1 # Copyright (C) 2006, 2007 Ulrik Sverdrup
3 # dragbox -- Commandline drag-and-drop tool for GNOME
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18 # USA
20 class Error(Exception):
21 pass
23 class ServiceUnavailable(Error):
24 pass
26 class NotEnabledError(ImportError, Error):
27 pass
29 def _clear_dbus_environment():
30 """
31 This is an evil run-on-import function to reset
32 dbus' environment
34 Here we try unsetting DBUS_SESSION_BUS_ADDRESS to
35 make dbus recover it from the current X session.
36 (debian bug #475448)
37 """
38 from os import unsetenv, getenv
39 from utils import print_debug
40 bus_address_env_name = "DBUS_SESSION_BUS_ADDRESS"
41 bus = None
43 print_debug("Unsetting %s, to defend against stale environment" %
44 bus_address_env_name)
45 unsetenv(bus_address_env_name)
47 _clear_dbus_environment()
48 try:
49 import dbus
50 from dbus.mainloop.glib import DBusGMainLoop
51 DBusGMainLoop(set_as_default=True)
52 from dbus.gobject_service import ExportedGObject
53 except:
54 raise NotEnabledError("Dbus not available")
56 import gobject
58 default_object_path = "/default"
59 service_interface = "org.gna.DragboxInterface"
60 default_service_name = "org.gna.dragbox"
62 class Service(ExportedGObject):
63 """
64 Provides a dbus server controller
66 Exported interface methods:
67 activate - sends signal activate
68 send_files - sends signal files-received
69 send_texts - sends signal texts-received
71 send_file, send_text: Send single objects. These
72 exported methods are for external methods to simplify
73 their interaction with dragbox.
75 data-requested signal: parameters send_callback and error_callback
76 on error, call error_callback with an exception instance. otherwise
77 send_callback should be called with two lists: datas, types.
78 """
79 __gtype_name__ = "Service"
81 @dbus.service.method(service_interface)
82 def send_file(self, f):
83 """
84 f: absolute path
85 """
86 self.send_files([f])
88 @dbus.service.method(service_interface)
89 def send_files(self, data):
90 """
91 data: list of absolute paths
92 """
93 self.emit("files-received", data)
95 @dbus.service.method(service_interface)
96 def send_text(self, t):
97 """
98 t: text string
99 """
100 self.send_texts([t])
102 @dbus.service.method(service_interface)
103 def send_texts(self, data):
105 data: list of text strings
107 self.emit("texts-received", data)
109 @dbus.service.method(service_interface)
110 def activate(self):
112 activate application (bring to front)
114 self.emit("activate")
116 @dbus.service.method(service_interface, out_signature="asas",
117 async_callbacks=("send_callback", "error_callback"))
118 def get_data(self, send_callback, error_callback):
120 activate application (bring to front)
122 self.emit("data-requested", send_callback, error_callback)
124 # See Service class declaration for
125 # documentation of the signals
126 gobject.type_register(Service)
127 gobject.signal_new("files-received", Service, gobject.SIGNAL_RUN_LAST,
128 gobject.TYPE_BOOLEAN, (gobject.TYPE_PYOBJECT, ))
129 gobject.signal_new("texts-received", Service, gobject.SIGNAL_RUN_LAST,
130 gobject.TYPE_BOOLEAN, (gobject.TYPE_PYOBJECT, ))
131 gobject.signal_new("activate", Service, gobject.SIGNAL_RUN_LAST,
132 gobject.TYPE_BOOLEAN, ())
133 gobject.signal_new("data-requested", Service, gobject.SIGNAL_RUN_LAST,
134 gobject.TYPE_BOOLEAN, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT))
136 def make_service(identifier=None):
138 Return a service object
140 identifier: The service identifier, or None to use the default
142 service_name = _make_service_name(identifier)
143 session_bus = dbus.SessionBus()
144 bus_name = dbus.service.BusName(service_name, bus=session_bus)
145 # return an instance of the Service
146 return Service(bus_name, object_path=default_object_path)
148 def _make_service_name(identifier):
150 Make a service name from the string identifier
152 Return default service name if identifier is None
154 if identifier:
155 accept = "abcdefghijklmnopqrstuvwxyz"
156 name = "".join(c for c in identifier.lower() if c in accept)
157 identifier = name
158 if not identifier:
159 return default_service_name
160 else:
161 return default_service_name + "." + identifier
163 def _get_dbus_interface(bus):
165 Return the interface of the main dbus object on the given bus
167 dbus_name = 'org.freedesktop.DBus'
168 dbus_object_path = '/org/freedesktop/DBus'
169 dbusobj = bus.get_object(dbus_name, dbus_object_path)
170 return dbus.Interface(dbusobj, dbus_name)
172 def _get_dbus_session_bus():
174 Get the dbus SessionBus
176 Raises ServiceUnavailable if dbus is not available
178 from utils import print_debug
179 bus = None
181 try:
182 bus = dbus.SessionBus()
183 except:
184 raise ServiceUnavailable("Could not get dbus session bus")
185 return bus
187 def list_names():
189 Yield available dragbox services by identifier
191 bus = _get_dbus_session_bus()
192 iface = _get_dbus_interface(bus)
193 bus_names = iface.ListNames()
194 for name in bus_names:
195 if name.startswith(default_service_name):
196 if name == default_service_name:
197 yield "(default)"
198 else:
199 basename = name.replace(default_service_name + ".", "")
200 yield basename
202 class Connection(object):
204 Tries to connect to previously started Service
206 def __init__(self, identifier=None):
208 Create a connection to a running instance
210 identifier: service identifier, or None to use the default
212 Throws ServiceUnavailable if no service found
214 bus = _get_dbus_session_bus()
216 service_name = _make_service_name(identifier)
217 # Check with dbus if service is available
218 dbusiface = _get_dbus_interface(bus)
219 if dbusiface.NameHasOwner(service_name):
220 proxy_obj = bus.get_object(service_name, default_object_path)
221 if proxy_obj:
222 self.iface = dbus.Interface(proxy_obj, service_interface)
223 return
224 self.iface = None
225 raise ServiceUnavailable("%s not found" % service_name)
227 def get_interface(self):
229 Returns the dbus interface to the "Service"
231 return self.iface