1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 HalServiceProvider component class
19 """
20
21
22 __maintainer__ = 'Philippe Normand <philippe@fluendo.com>'
23 __maintainer2__ = 'Benjamin Kampmann <benjamin@fluendo.com>'
24
25
26 from elisa.base_components.service_provider import ServiceProvider
27 from elisa.core.bus.bus_message import ComponentsLoaded, DeviceAction
28 from elisa.core import common
29 from elisa.core import component
30 import os, time, platform
31 from twisted.internet import threads
32
33 from elisa.extern.translation import gettexter, N_
34 T_ = gettexter('elisa-hal-service')
35
36 import dbus
37 if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
38 import dbus.glib
39 from dbus.exceptions import DBusException
40
41 try:
42 import gconf
43 except ImportError:
44 gconf = None
45
48
50 """
51 Retrieve the message of the DBus error. Usually something like
52 'org.freedesktop....'
53
54 @param exception: the DBus exception to analyze
55 @type exception: L{dbus.DBusException}
56 @rtype: string
57 """
58 if dbus.version < (0, 82, 0):
59 msg = exception.message
60 else:
61 msg = "%s: %s" % (exception._dbus_error_name, exception.message)
62 return msg
63
64
66 """
67 This class implements HAL support
68 """
69
73
97
106
113
116
119
136
138 """
139 Neutralize some of the volume_manager monitoring settings so
140 that the user won't see rhythmbox pop up when an iPod is
141 inserted (for example).
142 """
143 if gconf:
144 client = gconf.client_get_default()
145 path = '/desktop/gnome/volume_manager'
146 autoplay_cda = client.get_bool('%s/autoplay_cda' % path)
147 autoplay_dvd = client.get_bool('%s/autoplay_dvd' % path)
148 autobrowse = client.get_bool('%s/autobrowse' % path)
149 self.volume_manager_config = {'autoplay_cda': autoplay_cda,
150 'autoplay_dvd': autoplay_dvd,
151 'autobrowse': autobrowse}
152 for prop in self.volume_manager_config.keys():
153 client.set_bool('%s/%s' % (path, prop), False)
154
156 """
157 Restore the volume_manager gconf settings
158 """
159 if gconf:
160 client = gconf.client_get_default()
161 path = '/desktop/gnome/volume_manager'
162 for prop, value in self.volume_manager_config.iteritems():
163 client.set_bool('%s/%s' % (path, prop), value)
164
166 obj = self.bus.get_object('org.freedesktop.Hal', udi)
167 if obj != None:
168 device = dbus.Interface(obj, 'org.freedesktop.Hal.Device')
169 return device
170 return None
171
173 parent_udi = device.GetProperty(u'info.parent')
174 parent = self.get_device_with_udi(parent_udi)
175 if not parent.PropertyExists(u'portable_audio_player.type'):
176 return False
177 return parent.GetProperty(u'portable_audio_player.type').lower() == 'ipod'
178
179
180
182 name = device.GetProperty(u'info.product')
183 self.debug("ejecting: %r", name)
184 interface = 'org.freedesktop.Hal.Device.Storage'
185 method = device.get_dbus_method('Eject', dbus_interface=interface)
186
187 try:
188 method([])
189 except ValueError:
190
191
192 block_device = device.GetProperty(u'block.device')
193
194 threads.deferToThread(os.system, "eject %s" % block_device)
195
196
198 ignore = self._get_property(device, u'volume.ignore', False)
199
200 if ignore:
201 self.debug("volume.ignore property set on %r, can't mount it",
202 device)
203 return
204
205 prop_name = u'org.freedesktop.Hal.Device.Volume.method_names'
206 method_names = self._get_property(device, prop_name, [])
207
208 if 'Mount' not in method_names:
209 raise NotMountable()
210
211 interface = 'org.freedesktop.Hal.Device.Volume'
212 method = device.get_dbus_method('Mount', dbus_interface=interface)
213
214 name = device.GetProperty(u'info.product')
215 self.debug("mounting: %r ", name)
216
217 try:
218
219 method('', device.GetProperty(u'volume.fstype'),[])
220 except DBusException, exc:
221 already_mounted = 'org.freedesktop.Hal.Device.Volume.AlreadyMounted'
222 unavailable = 'org.freedesktop.Hal.Device.Volume.MountPointNotAvailable'
223 permission_denied = 'org.freedesktop.Hal.Device.Volume.PermissionDenied'
224
225 msg = get_dbus_error_message(exc)
226
227 if msg.startswith(already_mounted):
228 self.info("Already mounted")
229 elif msg.startswith(permission_denied):
230 idx = msg.index(permission_denied) + len(permission_denied) + 2
231 device_error = msg[idx:]
232 self.info("Permission denied: %s", device_error)
233 elif msg.startswith(unavailable):
234 return None
235 else:
236 raise
237
238 mount_point = self._get_mount_point(device)
239 return mount_point
240
256
258 value = default
259 if device.PropertyExists(prop_name):
260 value = device.GetProperty(prop_name)
261 return value
262
263
265 mount_point_prop = u'volume.label'
266
267 if udi not in self._hotplugged_devices:
268 device = self.get_device_with_udi(udi)
269 if device.QueryCapability("volume"):
270 try:
271 name = str(device.GetProperty('info.product'))
272 except dbus.DBusException:
273 name = ''
274
275 if self.parent_is_ipod(device):
276 fstype = 'ipod'
277 try:
278 point = self.mount_device(device)
279
280 self.new_volume_cb(udi, name, fstype, point,
281 ['audio',], True, 'ipod')
282 except NotMountable, exception:
283 pass
284 else:
285
286 parent_udi = device.GetProperty(u'info.parent')
287 parent = self.get_device_with_udi(parent_udi)
288
289 removable = self._get_property(parent, u'storage.removable',
290 False)
291
292 dvd = self._get_property(device, 'volume.disc.is_videodvd',
293 False)
294 audio_cd = self._get_property(device,
295 'volume.disc.has_audio',
296 False)
297 disc_is_partition = self._get_property(device,
298 'volume.disc.is_partition',
299 False)
300 is_partition = self._get_property(device,
301 'volume.is_partition',
302 False)
303 is_partition = disc_is_partition or is_partition
304
305 has_data = self._get_property(device,
306 'volume.disc.has_data', False)
307
308 self.debug("name: %r, dvd: %r, audio_cd: %r, partition: %r "\
309 "has_data: %r, removable: %r", name, dvd,
310 audio_cd, is_partition, has_data, removable)
311 if dvd:
312 if not name:
313 name = T_(N_('DVD'))
314 self.new_volume_cb(udi, name, 'dvd', '', ['video',],
315 removable, 'dvd')
316 elif audio_cd:
317 if not name:
318 name = T_(N_('Audio CD'))
319 fstype = 'cdda'
320
321
322 self.new_volume_cb(udi, name, fstype,'', ['audio',],
323 removable, 'audiocd')
324 elif is_partition or has_data or removable:
325 fstype = 'file'
326 if not name:
327 name = T_(N_('File device'))
328 try:
329 point = self.mount_device(device)
330 except NotMountable, exc:
331 pass
332 else:
333 self.new_volume_cb(udi,name, fstype, point,
334 ['audio', 'video', 'image'],
335 removable, 'usb_storage')
336
349
350 - def new_volume_cb(self, uid, name, fstype, mount_point, media_types=None,
351 removable=False, theme_icon=None):
352 """
353 Called when a new volume has been detected
354
355 @param name: Name of the device
356 @type name: string
357 @param fstype: Filesystem type
358 @type fstype: string
359 @param mount_point: Mount point
360 @type mount_point: string
361 @keyword media_types: media types that can be stored on the volume
362 @type media_types: list
363 @keyword removable: can the volume be removed?
364 @type removable: bool
365 @keyword theme_icon: the theme_icon the view should use to display
366 this volume
367 @type theme_icon: string
368 """
369 self._hotplugged_devices[uid] = ( name, fstype, mount_point )
370 self.debug("New volume found %r at %r", name, mount_point)
371
372 mount_point = "%s://%s" % (fstype, mount_point)
373 msg = DeviceAction(DeviceAction.ActionType.LOCATION_ADDED,
374 name, fstype, mount_point, media_types,
375 removable, theme_icon)
376 common.application.bus.send_message(msg)
377
394