1
/*
2
    <Class representing the USB devices currently connected to the system>
3
    Copyright (C) <2011>  <Lisa "shainer" Vitolo>
4
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Lesser General Public
7
    License as published by the Free Software Foundation; either
8
    version 2.1 of the License, or (at your option) any later version.
9
10
    This library 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 GNU
13
    Lesser General Public License for more details.
14
15
    You should have received a copy of the GNU Lesser General Public
16
    License along with this library; if not, write to the Free Software
17
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
*/
19
20
#include "devices.h"
21
22
using namespace Solid;
23
24
/*
25
 * Custom exception, mainly used for debugging and because I need something at the end of search methods
26
 * If it appears during the execution, something is not right!
27
 */
28
struct DeviceNotFoundException : public std::exception
29
{
30
  virtual const char* what() const throw()
31
  {
32
    return "[BUG] DeviceList: the device wasn't present in list";
33
  }
34
};
35
36
void DeviceList::initOperation()
37
{
38
  /*
39
   * If isNotifier is true, the program was called from the device notifier, so only the device that caused the
40
   * notifier to appear is considered at the beginning
41
   */
42
  if (isNotifier)
43
  {
44
    addDeviceToList(devNotifier);
45
  }
46
  else /* Otherwise, check for devices */
47
  {
48
    initList();
49
  }
50
  
51
  QDBusConnection dbus(QDBusConnection::systemBus());
52
  if (!dbus.isConnected())
53
  {
54
    qDebug() << "FATAL: error while connecting to DBus system";
55
  }
56
  const QString serviceName("org.freedesktop.UDisks");
57
  const QString servicePath("/org/freedesktop/UDisks");
58
  const QString signalAdd("DeviceAdded");
59
  const QString signalRm("DeviceRemoved");
60
  
61
  dbus.connect(serviceName, servicePath, serviceName, signalAdd, this, SLOT(addDevice(QDBusObjectPath)));
62
  dbus.connect(serviceName, servicePath, serviceName, signalRm, this, SLOT(removeDevice(QDBusObjectPath)));
63
}
64
65
void DeviceList::addDevice(QDBusObjectPath dev)
66
{
67
  QString fullPath = dev.path();
68
  
69
  /*
70
   * Sometimes when a new device is added two signals are sent: one for /dev/sdX and another one
71
   * for /dev/sdXN: we need only this second one
72
   */
73
  if (!(fullPath[fullPath.size() - 1].isNumber()))
74
  {
75
    return;
76
  }
77
  
78
  /*
79
   * Compares the current device with a list maintained by Solid to find the right Device object.
80
   */
81
  foreach (Device device, Device::allDevices())
82
  {
83
    if (fullPath.compare(device.udi()) == 0)
84
    {
85
      addDeviceToList(device);
86
    }
87
  }
88
}
89
90
USBDevice DeviceList::findDeviceFromPath(QString path)
91
{
92
  
93
  for (std::vector<USBDevice>::iterator it = devices.begin(); it < devices.end(); it++)
94
  {
95
    if (path.compare(it->getPath()) == 0)
96
    {
97
      return (*it);
98
    }
99
  }
100
  
101
  throw DeviceNotFoundException();
102
}
103
104
void DeviceList::setDeviceNotifier(Device const& dev)
105
{
106
  devNotifier = dev;
107
  isNotifier = true;
108
}
109
110
111
void DeviceList::removeDevice (QDBusObjectPath dev)
112
{
113
  QString path = getDevPath(dev.path());
114
  
115
  if (!(path[path.size() - 1].isNumber()))
116
  {
117
    return;
118
  }
119
  
120
  for (std::vector<USBDevice>::iterator it = devices.begin(); it < devices.end(); it++)
121
  {
122
    if (path.compare(it->getPath()) == 0)
123
    {
124
      emit refreshDevices((*it), false);
125
      devices.erase(it);
126
      return;
127
    }
128
  }
129
  
130
  throw DeviceNotFoundException();
131
}
132
133
QString DeviceList::getDevPath(QString s)
134
{
135
  return "/dev/" + s.section('/', 5, 5); /* removes useless stuff from the path */
136
}
137
138
139
void DeviceList::initList()
140
{
141
  int count = 0;
142
  
143
  foreach(const Device &i, Device::listFromType(DeviceInterface::StorageAccess, QString()))
144
  {
145
    if(i.parent().is<StorageDrive>() && i.parent().as<StorageDrive>()->bus() == StorageDrive::Usb)
146
    {
147
      addDeviceToList(i);
148
      count++;
149
    }
150
  }
151
  
152
  /*
153
   * **HACK ALERT**
154
   * If no device is present, the DeviceRemoved signal is never sent (of course!) so the GUI doesn't receive any notify
155
   * and doesn't disable the GUI as it normally do when there's no device.
156
   * So a dummy device (no parameters are added, empty constructor) is created to trigger the right control in the GUI.
157
   */
158
  if (count == 0)
159
  {
160
    USBDevice dummy;
161
    emit refreshDevices(dummy, false);
162
  }
163
}
164
165
void DeviceList::addDeviceToList(Device d)
166
{
167
  QString path = getDevPath(d.udi());  
168
  USBDevice n(path, d);
169
  devices.push_back(n);
170
  emit refreshDevices(n, true);
171
}
172
173
#include "devices.moc"