only call IPlayerCallback::OnPlayBackSpeedChanged if the speed has actually changed
[vuplus_xbmc] / xbmc / storage / linux / DeviceKitDisksProvider.cpp
1 /*
2  *      Copyright (C) 2005-2009 Team XBMC
3  *      http://www.xbmc.org
4  *
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, or (at your option)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21 #include "DeviceKitDisksProvider.h"
22 #ifdef HAS_DBUS
23 #include "settings/AdvancedSettings.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "utils/log.h"
26 #include "utils/URIUtils.h"
27
28 void CDeviceKitDiskDeviceOldAPI::Update()
29 {
30   CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
31
32   m_isFileSystem = CStdString(properties["id-usage"].asString()) == "filesystem";
33   if (m_isFileSystem)
34   {
35     m_UDI         = properties["id-uuid"].asString();
36     m_Label       = properties["id-label"].asString();
37     m_FileSystem  = properties["id-type"].asString();
38   }
39   else
40   {
41     m_UDI.clear();
42     m_Label.clear();
43     m_FileSystem.clear();
44   }
45   m_isMounted   = properties["device-is-mounted"].asBoolean();
46   if (m_isMounted && properties["device-mount-paths"].size() > 0)
47     m_MountPath   = properties["device-mount-paths"][0].asString();
48   else
49     m_MountPath.clear();
50
51   m_PartitionSizeGiB = properties["partition-size"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
52   m_isPartition = properties["device-is-partition"].asBoolean();
53   m_isSystemInternal = properties["device-is-system-internal"].asBoolean();
54   m_isOptical = properties["device-is-optical-disc"].asBoolean();
55   if (m_isPartition)
56     m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["partition-slave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "device-is-removable").asBoolean();
57   else
58     m_isRemovable = properties["device-is-removable"].asBoolean();
59 }
60
61 void CDeviceKitDiskDeviceNewAPI::Update()
62 {
63   CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
64
65   m_isFileSystem = CStdString(properties["IdUsage"].asString()) == "filesystem";
66   if (m_isFileSystem)
67   {
68     m_UDI         = properties["IdUuid"].asString();
69     m_Label       = properties["IdLabel"].asString();
70     m_FileSystem  = properties["IdType"].asString();
71   }
72   else
73   {
74     m_UDI.clear();
75     m_Label.clear();
76     m_FileSystem.clear();
77   }
78
79   m_isMounted   = properties["DeviceIsMounted"].asBoolean();
80   if (m_isMounted && properties["DeviceMountPaths"].size() > 0)
81     m_MountPath   = properties["DeviceMountPaths"][0].asString();
82   else
83     m_MountPath.clear();
84
85   m_PartitionSizeGiB = properties["PartitionSize"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
86   m_isPartition = properties["DeviceIsPartition"].asBoolean();
87   m_isSystemInternal = properties["DeviceIsSystemInternal"].asBoolean();
88   m_isOptical = properties["DeviceIsOpticalDisc"].asBoolean();
89   if (m_isPartition)
90     m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["PartitionSlave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "DeviceIsRemovable").asBoolean();
91   else
92     m_isRemovable = properties["DeviceIsRemovable"].asBoolean();
93 }
94
95 CDeviceKitDiskDevice::CDeviceKitDiskDevice(const char *DeviceKitUDI)
96 {
97   m_DeviceKitUDI = DeviceKitUDI;
98   m_UDI = "";
99   m_MountPath = "";
100   m_FileSystem = "";
101   m_isMounted = false;
102   m_isMountedByUs = false;
103   m_isRemovable = false;
104   m_isPartition = false;
105   m_isFileSystem = false;
106   m_isSystemInternal = false;
107   m_isOptical = false;
108   m_PartitionSizeGiB = 0.0f;
109 }
110
111 bool CDeviceKitDiskDevice::Mount()
112 {
113   if (!m_isMounted && !m_isSystemInternal && m_isFileSystem)
114   {
115     CLog::Log(LOGDEBUG, "DeviceKit.Disks: Mounting %s", m_DeviceKitUDI.c_str());
116     CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemMount");
117     message.AppendArgument("");
118     const char *array[] = {};
119     message.AppendArgument(array, 0);
120
121     DBusMessage *reply = message.SendSystem();
122     if (reply)
123     {
124       char *mountPoint;
125       if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &mountPoint, DBUS_TYPE_INVALID))
126       {
127         m_MountPath = mountPoint;
128         CLog::Log(LOGDEBUG, "DeviceKit.Disks: Sucessfully mounted %s on %s", m_DeviceKitUDI.c_str(), mountPoint);
129         m_isMountedByUs = m_isMounted = true;
130       }
131     }
132
133     return m_isMounted;
134   }
135   else
136     CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to mount %s", toString().c_str());
137
138   return false;
139 }
140
141 bool CDeviceKitDiskDevice::UnMount()
142 {
143   if (m_isMounted && !m_isSystemInternal && m_isFileSystem)
144   {
145     CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemUnmount");
146
147     const char *array[1];
148     message.AppendArgument(array, 0);
149
150     DBusMessage *reply = message.SendSystem();
151     if (reply)
152       m_isMountedByUs = m_isMounted = false;
153
154     return !m_isMounted;
155   }
156   else
157     CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to unmount %s", toString().c_str());
158
159   return false;
160 }
161
162 CMediaSource CDeviceKitDiskDevice::ToMediaShare()
163 {
164   CMediaSource source;
165   source.strPath = m_MountPath;
166   if (m_Label.empty())
167     source.strName.Format("%.1f GB %s", m_PartitionSizeGiB, g_localizeStrings.Get(155).c_str());
168   else
169     source.strName = m_Label;
170   if (m_isOptical)
171     source.m_iDriveType = CMediaSource::SOURCE_TYPE_DVD;
172   else if (m_isSystemInternal)
173     source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
174   else
175     source.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
176   source.m_ignore = true;
177   return source;
178 }
179
180 bool CDeviceKitDiskDevice::IsApproved()
181 {
182   return (m_isFileSystem && m_isMounted && m_UDI.length() > 0 && (m_FileSystem.length() > 0 && !m_FileSystem.Equals("swap")) && !m_MountPath.Equals("/")) || m_isOptical;
183 }
184
185 #define BOOL2SZ(b) ((b) ? "true" : "false")
186
187 CStdString CDeviceKitDiskDevice::toString()
188 {
189   CStdString str;
190   str.Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
191       "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
192       "IsOptical %s",
193       m_DeviceKitUDI.c_str(), BOOL2SZ(m_isFileSystem), m_FileSystem,
194       BOOL2SZ(m_isSystemInternal), BOOL2SZ(m_isMounted),
195       BOOL2SZ(m_isRemovable), BOOL2SZ(m_isPartition), BOOL2SZ(m_isOptical));
196
197   return str;
198 }
199
200 CDeviceKitDisksProvider::CDeviceKitDisksProvider()
201 {
202   dbus_error_init (&m_error);
203   // TODO: do not use dbus_connection_pop_message() that requires the use of a
204   // private connection
205   m_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_error);
206   dbus_connection_set_exit_on_disconnect(m_connection, false);
207
208   dbus_bus_add_match(m_connection, "type='signal',interface='org.freedesktop.DeviceKit.Disks'", &m_error);
209   dbus_connection_flush(m_connection);
210   if (dbus_error_is_set(&m_error))
211   {
212     CLog::Log(LOGERROR, "DeviceKit.Disks: Failed to attach to signal %s", m_error.message);
213     dbus_connection_close(m_connection);
214     dbus_connection_unref(m_connection);
215     m_connection = NULL;
216   }
217 }
218
219 CDeviceKitDisksProvider::~CDeviceKitDisksProvider()
220 {
221   DeviceMap::iterator itr;
222
223   for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
224     delete m_AvailableDevices[itr->first];
225
226   m_AvailableDevices.clear();
227
228   if (m_connection)
229   {
230     dbus_connection_close(m_connection);
231     dbus_connection_unref(m_connection);
232     m_connection = NULL;
233   }
234
235   dbus_error_free (&m_error);
236 }
237
238 void CDeviceKitDisksProvider::Initialize()
239 {
240   CLog::Log(LOGDEBUG, "Selected DeviceKit.Disks as storage provider");
241   m_DaemonVersion = atoi(CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "DaemonVersion").asString().c_str());
242   CLog::Log(LOGDEBUG, "DeviceKit.Disks: DaemonVersion %i", m_DaemonVersion);
243
244   CLog::Log(LOGDEBUG, "DeviceKit.Disks: Querying available devices");
245   std::vector<CStdString> devices = EnumerateDisks();
246   for (unsigned int i = 0; i < devices.size(); i++)
247     DeviceAdded(devices[i].c_str(), NULL);
248 }
249
250 bool CDeviceKitDisksProvider::Eject(CStdString mountpath)
251 {
252   DeviceMap::iterator itr;
253   CStdString path(mountpath);
254   URIUtils::RemoveSlashAtEnd(path);
255
256   for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
257   {
258     CDeviceKitDiskDevice *device = itr->second;
259     if (device->m_MountPath.Equals(path))
260       return device->UnMount();
261   }
262
263   return false;
264 }
265
266 std::vector<CStdString> CDeviceKitDisksProvider::GetDiskUsage()
267 {
268   std::vector<CStdString> devices;
269   DeviceMap::iterator itr;
270
271   for(itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
272   {
273     CDeviceKitDiskDevice *device = itr->second;
274     if (device->m_isMounted)
275     {
276       CStdString str;
277       str.Format("%s %.1f GiB", device->m_MountPath.c_str(), device->m_PartitionSizeGiB);
278       devices.push_back(str);
279     }
280   }
281
282   return devices;
283 }
284
285 bool CDeviceKitDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
286 {
287   bool result = false;
288   if (m_connection)
289   {
290     dbus_connection_read_write(m_connection, 0);
291     DBusMessage *msg = dbus_connection_pop_message(m_connection);
292
293     if (msg)
294     {
295       char *object;
296       if (dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &object, DBUS_TYPE_INVALID))
297       {
298         result = true;
299         if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceAdded"))
300           DeviceAdded(object, callback);
301         else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceRemoved"))
302           DeviceRemoved(object, callback);
303         else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceChanged"))
304           DeviceChanged(object, callback);
305       }
306       dbus_message_unref(msg);
307     }
308   }
309   return result;
310 }
311
312 bool CDeviceKitDisksProvider::HasDeviceKitDisks()
313 {
314   bool hasDeviceKitDisks = false;
315   CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
316
317   DBusError error;
318   dbus_error_init (&error);
319   DBusConnection *con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
320
321   if (con)
322     message.Send(con, &error);
323
324   if (!dbus_error_is_set(&error))
325     hasDeviceKitDisks = true;
326   else
327     CLog::Log(LOGDEBUG, "DeviceKit.Disks: %s - %s", error.name, error.message);
328
329   dbus_error_free (&error);
330   if (con)
331     dbus_connection_unref(con);
332
333   return hasDeviceKitDisks;
334 }
335
336 void CDeviceKitDisksProvider::DeviceAdded(const char *object, IStorageEventsCallback *callback)
337 {
338   CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded (%s)", object);
339
340   if (m_AvailableDevices[object])
341   {
342     CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceAdded on an indexed disk");
343     delete m_AvailableDevices[object];
344   }
345
346   CDeviceKitDiskDevice *device = NULL;
347   if (m_DaemonVersion >= 7)
348     device = new CDeviceKitDiskDeviceNewAPI(object);
349   else
350     device = new CDeviceKitDiskDeviceOldAPI(object);
351   m_AvailableDevices[object] = device;
352
353   if (g_advancedSettings.m_handleMounting)
354     device->Mount();
355
356   CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded - %s", device->toString().c_str());
357   if (device->m_isMounted && device->IsApproved())
358   {
359     CLog::Log(LOGNOTICE, "DeviceKit.Disks: Added %s", device->m_MountPath.c_str());
360     if (callback)
361       callback->OnStorageAdded(device->m_Label, device->m_MountPath);
362   }
363 }
364
365 void CDeviceKitDisksProvider::DeviceRemoved(const char *object, IStorageEventsCallback *callback)
366 {
367   CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceRemoved (%s)", object);
368
369   CDeviceKitDiskDevice *device = m_AvailableDevices[object];
370   if (device)
371   {
372     if (device->m_isMounted && callback)
373       callback->OnStorageUnsafelyRemoved(device->m_Label);
374
375     delete m_AvailableDevices[object];
376     m_AvailableDevices.erase(object);
377   }
378 }
379
380 void CDeviceKitDisksProvider::DeviceChanged(const char *object, IStorageEventsCallback *callback)
381 {
382   CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged (%s)", object);
383
384   CDeviceKitDiskDevice *device = m_AvailableDevices[object];
385   if (device == NULL)
386   {
387     CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceChanged on an unindexed disk");
388     DeviceAdded(object, callback);
389   }
390   else
391   {
392     bool mounted = device->m_isMounted;
393     device->Update();
394     if (!mounted && device->m_isMounted && callback)
395       callback->OnStorageAdded(device->m_Label, device->m_MountPath);
396     else if (mounted && !device->m_isMounted && callback)
397       callback->OnStorageSafelyRemoved(device->m_Label);
398
399     CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged - %s", device->toString().c_str());
400   }
401 }
402
403 std::vector<CStdString> CDeviceKitDisksProvider::EnumerateDisks()
404 {
405   std::vector<CStdString> devices;
406   CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
407   DBusMessage *reply = message.SendSystem();
408   if (reply)
409   {
410     char** disks  = NULL;
411     int    length = 0;
412
413     if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &disks, &length, DBUS_TYPE_INVALID))
414     {
415       for (int i = 0; i < length; i++)
416         devices.push_back(disks[i]);
417
418       dbus_free_string_array(disks);
419     }
420   }
421
422   return devices;
423 }
424
425 void CDeviceKitDisksProvider::GetDisks(VECSOURCES& devices, bool EnumerateRemovable)
426 {
427   DeviceMap::iterator itr;
428
429   for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
430   {
431     CDeviceKitDiskDevice *device = itr->second;
432     if (device && device->IsApproved() && device->m_isSystemInternal != EnumerateRemovable)
433       devices.push_back(device->ToMediaShare());
434   }
435 }
436 #endif