1 /*
2     Copyright 2006 Kevin Ottens <ervin@kde.org>
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) version 3, or any
8     later version accepted by the membership of KDE e.V. (or its
9     successor approved by the membership of KDE e.V.), which shall
10     act as a proxy defined in Section 6 of version 3 of the license.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "halcdrom.h"
22 
23 #include <QtCore/QStringList>
24 #include <QtDBus/QDBusInterface>
25 #include <QtDBus/QDBusReply>
26 #include <QtDBus/QDBusError>
27 #include <QtDBus/QDBusVariant>
28 
29 #include "halfstabhandling.h"
30 
31 using namespace Solid::Backends::Hal;
32 
Cdrom(HalDevice * device)33 Cdrom::Cdrom(HalDevice *device)
34     : Storage(device), m_ejectInProgress(false)
35 {
36     connect(device, SIGNAL(conditionRaised(QString,QString)),
37              this, SLOT(slotCondition(QString,QString)));
38     m_device->registerAction("eject", this,
39                              SLOT(slotEjectRequested()),
40                              SLOT(slotEjectDone(int,QString)));
41 }
42 
~Cdrom()43 Cdrom::~Cdrom()
44 {
45 
46 }
47 
48 
supportedMedia() const49 Solid::OpticalDrive::MediumTypes Cdrom::supportedMedia() const
50 {
51     Solid::OpticalDrive::MediumTypes supported;
52 
53     QMap<Solid::OpticalDrive::MediumType, QString> map;
54     map[Solid::OpticalDrive::Cdr] = "storage.cdrom.cdr";
55     map[Solid::OpticalDrive::Cdrw] = "storage.cdrom.cdrw";
56     map[Solid::OpticalDrive::Dvd] = "storage.cdrom.dvd";
57     map[Solid::OpticalDrive::Dvdr] = "storage.cdrom.dvdr";
58     map[Solid::OpticalDrive::Dvdrw] ="storage.cdrom.dvdrw";
59     map[Solid::OpticalDrive::Dvdram] ="storage.cdrom.dvdram";
60     map[Solid::OpticalDrive::Dvdplusr] ="storage.cdrom.dvdplusr";
61     map[Solid::OpticalDrive::Dvdplusrw] ="storage.cdrom.dvdplusrw";
62     map[Solid::OpticalDrive::Dvdplusdl] ="storage.cdrom.dvdplusrdl";
63     map[Solid::OpticalDrive::Dvdplusdlrw] ="storage.cdrom.dvdplusrwdl";
64     map[Solid::OpticalDrive::Bd] ="storage.cdrom.bd";
65     map[Solid::OpticalDrive::Bdr] ="storage.cdrom.bdr";
66     map[Solid::OpticalDrive::Bdre] ="storage.cdrom.bdre";
67     map[Solid::OpticalDrive::HdDvd] ="storage.cdrom.hddvd";
68     map[Solid::OpticalDrive::HdDvdr] ="storage.cdrom.hddvdr";
69     map[Solid::OpticalDrive::HdDvdrw] ="storage.cdrom.hddvdrw";
70 
71     foreach (const Solid::OpticalDrive::MediumType type, map.keys())
72     {
73         if (m_device->prop(map[type]).toBool())
74         {
75             supported|= type;
76         }
77     }
78 
79     return supported;
80 }
81 
readSpeed() const82 int Cdrom::readSpeed() const
83 {
84     return m_device->prop("storage.cdrom.read_speed").toInt();
85 }
86 
writeSpeed() const87 int Cdrom::writeSpeed() const
88 {
89     return m_device->prop("storage.cdrom.write_speed").toInt();
90 }
91 
writeSpeeds() const92 QList<int> Cdrom::writeSpeeds() const
93 {
94     QList<int> speeds;
95     QStringList speed_strlist = m_device->prop("storage.cdrom.write_speeds").toStringList();
96 
97     foreach (const QString &speed_str, speed_strlist)
98     {
99         speeds << speed_str.toInt();
100     }
101 
102     return speeds;
103 }
104 
slotCondition(const QString & name,const QString &)105 void Cdrom::slotCondition(const QString &name, const QString &/*reason */)
106 {
107     if (name == "EjectPressed")
108     {
109         emit ejectPressed(m_device->udi());
110     }
111 }
112 
eject()113 bool Cdrom::eject()
114 {
115     if (m_ejectInProgress) {
116         return false;
117     }
118     m_ejectInProgress = true;
119     m_device->broadcastActionRequested("eject");
120 
121     if (FstabHandling::isInFstab(m_device->prop("block.device").toString())) {
122         return callSystemEject();
123     } else {
124         return callHalDriveEject();
125     }
126 }
127 
slotEjectRequested()128 void Cdrom::slotEjectRequested()
129 {
130     m_ejectInProgress = true;
131     emit ejectRequested(m_device->udi());
132 }
133 
callHalDriveEject()134 bool Cdrom::callHalDriveEject()
135 {
136     QString udi = m_device->udi();
137     QString interface = "org.freedesktop.Hal.Device.Storage";
138 
139     // HACK: Eject doesn't work on cdrom drives when there's a mounted disc,
140     // let's try to workaround this by calling a child volume...
141     if (m_device->prop("storage.removable.media_available").toBool()) {
142         QDBusInterface manager("org.freedesktop.Hal",
143                                "/org/freedesktop/Hal/Manager",
144                                "org.freedesktop.Hal.Manager",
145                                QDBusConnection::systemBus());
146 
147         QDBusReply<QStringList> reply = manager.call("FindDeviceStringMatch", "info.parent", udi);
148 
149         if (reply.isValid())
150         {
151             const QStringList udis = reply;
152             if (!udis.isEmpty()) {
153                 udi = udis[0];
154                 interface = "org.freedesktop.Hal.Device.Volume";
155             }
156         }
157     }
158 
159     QDBusConnection c = QDBusConnection::systemBus();
160     QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.Hal", udi,
161                                                       interface, "Eject");
162 
163     msg << QStringList();
164 
165 
166     return c.callWithCallback(msg, this,
167                               SLOT(slotDBusReply(QDBusMessage)),
168                               SLOT(slotDBusError(QDBusError)));
169 }
170 
callSystemEject()171 bool Solid::Backends::Hal::Cdrom::callSystemEject()
172 {
173     const QString device = m_device->prop("block.device").toString();
174     m_process = FstabHandling::callSystemCommand("eject", device,
175                                                  this, SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
176 
177     return m_process!=nullptr;
178 }
179 
slotDBusReply(const QDBusMessage &)180 void Cdrom::slotDBusReply(const QDBusMessage &/*reply*/)
181 {
182     m_ejectInProgress = false;
183     m_device->broadcastActionDone("eject");
184 }
185 
slotDBusError(const QDBusError & error)186 void Cdrom::slotDBusError(const QDBusError &error)
187 {
188     m_ejectInProgress = false;
189 
190     // TODO: Better error reporting here
191     m_device->broadcastActionDone("eject", Solid::UnauthorizedOperation,
192                                   QString(error.name()+": "+error.message()));
193 }
194 
slotProcessFinished(int exitCode,QProcess::ExitStatus exitStatus)195 void Solid::Backends::Hal::Cdrom::slotProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
196 {
197     Q_UNUSED(exitStatus);
198     if (m_ejectInProgress) {
199         m_ejectInProgress = false;
200 
201         if (exitCode==0) {
202             m_device->broadcastActionDone("eject");
203         } else {
204             m_device->broadcastActionDone("eject", Solid::UnauthorizedOperation,
205                                           m_process->readAllStandardError());
206         }
207     }
208 
209     delete m_process;
210 }
211 
slotEjectDone(int error,const QString & errorString)212 void Cdrom::slotEjectDone(int error, const QString &errorString)
213 {
214     m_ejectInProgress = false;
215     emit ejectDone(static_cast<Solid::ErrorType>(error), errorString, m_device->udi());
216 }
217 
218 #include "backends/hal/moc_halcdrom.cpp"
219