summaryrefslogtreecommitdiffstats
path: root/kioslave/media/mediamanager
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /kioslave/media/mediamanager
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kioslave/media/mediamanager')
-rw-r--r--kioslave/media/mediamanager/Makefile.am32
-rw-r--r--kioslave/media/mediamanager/backendbase.cpp26
-rw-r--r--kioslave/media/mediamanager/backendbase.h35
-rw-r--r--kioslave/media/mediamanager/fstabbackend.cpp483
-rw-r--r--kioslave/media/mediamanager/fstabbackend.h68
-rw-r--r--kioslave/media/mediamanager/halbackend.cpp1345
-rw-r--r--kioslave/media/mediamanager/halbackend.h228
-rw-r--r--kioslave/media/mediamanager/linuxcdpolling.cpp585
-rw-r--r--kioslave/media/mediamanager/linuxcdpolling.h86
-rw-r--r--kioslave/media/mediamanager/mediadirnotify.cpp124
-rw-r--r--kioslave/media/mediamanager/mediadirnotify.h47
-rw-r--r--kioslave/media/mediamanager/medialist.cpp288
-rw-r--r--kioslave/media/mediamanager/medialist.h79
-rw-r--r--kioslave/media/mediamanager/mediamanager.cpp342
-rw-r--r--kioslave/media/mediamanager/mediamanager.desktop141
-rw-r--r--kioslave/media/mediamanager/mediamanager.h90
-rw-r--r--kioslave/media/mediamanager/removablebackend.cpp180
-rw-r--r--kioslave/media/mediamanager/removablebackend.h52
18 files changed, 4231 insertions, 0 deletions
diff --git a/kioslave/media/mediamanager/Makefile.am b/kioslave/media/mediamanager/Makefile.am
new file mode 100644
index 000000000..45289a9eb
--- /dev/null
+++ b/kioslave/media/mediamanager/Makefile.am
@@ -0,0 +1,32 @@
+kde_module_LTLIBRARIES = kded_mediamanager.la
+
+if include_media_halbackend
+HALBACKEND_INCS = $(HAL_INCS) $(DBUS_INCS) $(DBUSQT_INCS)
+endif
+
+METASOURCES = AUTO
+INCLUDES = -I$(srcdir)/../libmediacommon -I../libmediacommon $(HALBACKEND_INCS) $(all_includes)
+
+if include_media_halbackend
+HALBACKEND_LIB = libhalbackend.la
+libhalbackend_la_SOURCES = halbackend.cpp
+libhalbackend_la_LDFLAGS = -avoid-version $(all_libraries) -no-undefined
+libhalbackend_la_LIBADD = $(HAL_LIBS) $(DBUS_LIBS) $(DBUSQT_LIBS)
+endif
+
+if include_media_linuxcdpolling
+LINUXCDPOLLING_LIB = liblinuxcdpolling.la
+liblinuxcdpolling_la_SOURCES = linuxcdpolling.cpp
+liblinuxcdpolling_la_LDFLAGS = -avoid-version $(all_libraries) -no-undefined
+endif
+
+noinst_LTLIBRARIES = $(LINUXCDPOLLING_LIB) $(HALBACKEND_LIB)
+
+kded_mediamanager_la_SOURCES = mediamanager.cpp mediamanager.skel medialist.cpp backendbase.cpp fstabbackend.cpp removablebackend.cpp mediadirnotify.cpp mediadirnotify.skel
+kded_mediamanager_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_mediamanager_la_LIBADD = $(LIB_KSYCOCA) ../libmediacommon/libmediacommon.la $(HALBACKEND_LIB) $(LINUXCDPOLLING_LIB)
+
+
+servicesdir = $(kde_servicesdir)/kded
+services_DATA = mediamanager.desktop
+
diff --git a/kioslave/media/mediamanager/backendbase.cpp b/kioslave/media/mediamanager/backendbase.cpp
new file mode 100644
index 000000000..157acfca5
--- /dev/null
+++ b/kioslave/media/mediamanager/backendbase.cpp
@@ -0,0 +1,26 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "backendbase.h"
+
+BackendBase::BackendBase(MediaList &list)
+ : m_mediaList(list)
+{
+
+}
+
diff --git a/kioslave/media/mediamanager/backendbase.h b/kioslave/media/mediamanager/backendbase.h
new file mode 100644
index 000000000..689522d1f
--- /dev/null
+++ b/kioslave/media/mediamanager/backendbase.h
@@ -0,0 +1,35 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _BACKENDBASE_H_
+#define _BACKENDBASE_H_
+
+#include "medialist.h"
+
+class BackendBase
+{
+protected:
+ BackendBase(MediaList &list);
+public:
+ virtual ~BackendBase() { }
+
+protected:
+ MediaList &m_mediaList;
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/fstabbackend.cpp b/kioslave/media/mediamanager/fstabbackend.cpp
new file mode 100644
index 000000000..4ffcf4b2d
--- /dev/null
+++ b/kioslave/media/mediamanager/fstabbackend.cpp
@@ -0,0 +1,483 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+ Linux CD/DVD detection
+ Copyright (c) 2005 Bernhard Rosenkraenzer <bero arklinux org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "fstabbackend.h"
+
+#ifdef __linux__
+// For CD/DVD drive detection
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdint.h>
+#define CDROM_GET_CAPABILITY 0x5331
+#define CDSL_CURRENT ((int) (~0U>>1))
+#define CDC_DVD_R 0x10000 /* drive can write DVD-R */
+#define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */
+#define CDC_CD_R 0x2000 /* drive is a CD-R */
+#define CDC_CD_RW 0x4000 /* drive is a CD-RW */
+#define CDC_DVD 0x8000 /* drive is a DVD */
+#include <qfile.h>
+#endif
+
+#include <klocale.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kurl.h>
+#include <kmountpoint.h>
+#include <kstandarddirs.h>
+
+#ifdef _OS_SOLARIS_
+#define FSTAB "/etc/vfstab"
+#define MTAB "/etc/mnttab"
+#else
+#define FSTAB "/etc/fstab"
+#define MTAB "/etc/mtab"
+#endif
+
+
+
+FstabBackend::FstabBackend(MediaList &list, bool networkSharesOnly)
+ : QObject(), BackendBase(list), m_networkSharesOnly(networkSharesOnly)
+{
+ KDirWatch::self()->addFile(MTAB);
+ KDirWatch::self()->addFile(FSTAB);
+
+ connect( KDirWatch::self(), SIGNAL( dirty(const QString&) ),
+ this, SLOT( slotDirty(const QString&) ) );
+
+ handleFstabChange(false);
+ handleMtabChange(false);
+
+ KDirWatch::self()->startScan();
+
+#ifdef Q_OS_FREEBSD
+ connect( &m_mtabTimer, SIGNAL( timeout() ),
+ this, SLOT( handleMtabChange() ) );
+ m_mtabTimer.start(250);
+#endif
+}
+
+FstabBackend::~FstabBackend()
+{
+ QStringList::iterator it = m_mtabIds.begin();
+ QStringList::iterator end = m_mtabIds.end();
+
+ for (; it!=end; ++it)
+ {
+ m_mediaList.removeMedium(*it, false);
+ }
+
+ it = m_fstabIds.begin();
+ end = m_fstabIds.end();
+
+ for (; it!=end; ++it)
+ {
+ m_mediaList.removeMedium(*it, false);
+ }
+ KDirWatch::self()->removeFile(FSTAB);
+ KDirWatch::self()->removeFile(MTAB);
+}
+
+QString FstabBackend::mount( const QString &_udi )
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ return i18n("No such medium: %1").arg(_udi);
+ KIO::Job* job = KIO::mount( false, 0, medium->deviceNode(), medium->mountPoint());
+ KIO::NetAccess::synchronousRun( job, 0 );
+ return QString::null;
+}
+
+QString FstabBackend::unmount( const QString &_udi )
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ return i18n("No such medium: %1").arg(_udi);
+ KIO::Job* job = KIO::unmount( medium->mountPoint(), false);
+ KIO::NetAccess::synchronousRun( job, 0 );
+ return QString::null;
+}
+
+void FstabBackend::slotDirty(const QString &path)
+{
+ if (path==MTAB)
+ {
+ handleMtabChange();
+ }
+ else if (path==FSTAB)
+ {
+ handleFstabChange();
+ }
+}
+
+bool inExclusionPattern(KMountPoint *mount, bool networkSharesOnly)
+{
+ if ( mount->mountType() == "swap"
+ || mount->mountType() == "tmpfs"
+ || mount->mountType() == "sysfs"
+ || mount->mountType() == "fdescfs"
+ || mount->mountType() == "kernfs"
+ || mount->mountType() == "usbfs"
+ || mount->mountType().contains( "proc" )
+ || mount->mountType() == "unknown"
+ || mount->mountType() == "none"
+ || mount->mountType() == "sunrpc"
+ || mount->mountedFrom() == "none"
+ || mount->mountedFrom() == "tmpfs"
+ || mount->mountedFrom().find("shm") != -1
+ || mount->mountPoint() == "/dev/swap"
+ || mount->mountPoint() == "/dev/pts"
+ || mount->mountPoint().find("/proc") == 0
+ || mount->mountPoint().find("/sys") == 0
+
+ // We might want to display only network shares
+ // since HAL doesn't handle them
+ || ( networkSharesOnly
+ && mount->mountType().find( "smb" ) == -1
+ && mount->mountType().find( "cifs" ) == -1
+ && mount->mountType().find( "nfs" ) == -1
+ )
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void FstabBackend::handleMtabChange(bool allowNotification)
+{
+ QStringList new_mtabIds;
+ KMountPoint::List mtab = KMountPoint::currentMountPoints();
+
+ KMountPoint::List::iterator it = mtab.begin();
+ KMountPoint::List::iterator end = mtab.end();
+
+ for (; it!=end; ++it)
+ {
+ QString dev = (*it)->mountedFrom();
+ QString mp = (*it)->mountPoint();
+ QString fs = (*it)->mountType();
+
+ if ( ::inExclusionPattern(*it, m_networkSharesOnly) ) continue;
+
+ /* Did we know this already before ? If yes, then
+ nothing has changed, do not stat the mount point. Avoids
+ hang if network shares are stalling */
+ QString mtabEntry = dev + "*" + mp + "*" + fs;
+ if(m_mtabEntries.contains(mtabEntry)) {
+ new_mtabIds += m_mtabEntries[mtabEntry];
+ continue;
+ }
+
+ QString id = generateId(dev, mp);
+ new_mtabIds+=id;
+ m_mtabEntries[mtabEntry] = id;
+
+ if ( !m_mtabIds.contains(id) && m_fstabIds.contains(id) )
+ {
+ QString mime, icon, label;
+ guess(dev, mp, fs, true, mime, icon, label);
+ m_mediaList.changeMediumState(id, true, false,
+ mime, icon, label);
+ }
+#if 0
+ else if ( !m_mtabIds.contains(id) )
+ {
+ QString name = generateName(dev, fs);
+
+ Medium *m = new Medium(id, name);
+
+ m->mountableState(dev, mp, fs, true);
+
+ QString mime, icon, label;
+ guess(dev, mp, fs, true, mime, icon, label);
+
+ m->setMimeType(mime);
+ m->setIconName(icon);
+ m->setLabel(label);
+
+ m_mediaList.addMedium(m, notificationAllowed);
+ }
+#endif
+ }
+
+ QStringList::iterator it2 = m_mtabIds.begin();
+ QStringList::iterator end2 = m_mtabIds.end();
+
+ for (; it2!=end2; ++it2)
+ {
+ if ( !new_mtabIds.contains(*it2) && m_fstabIds.contains(*it2) )
+ {
+ const Medium *medium = m_mediaList.findById(*it2);
+
+ QString dev = medium->deviceNode();
+ QString mp = medium->mountPoint();
+ QString fs = medium->fsType();
+
+
+ QString mtabEntry = dev + "*" + mp + "*" + fs;
+ m_mtabEntries.remove(mtabEntry);
+
+ QString mime, icon, label;
+ guess(dev, mp, fs, false, mime, icon, label);
+
+ m_mediaList.changeMediumState(*it2, false, false,
+ mime, icon, label);
+ }
+#if 0
+ else if ( !new_mtabIds.contains(*it2) )
+ {
+ m_mediaList.removeMedium(*it2, allowNotification);
+ }
+#endif
+ }
+
+ m_mtabIds = new_mtabIds;
+}
+
+void FstabBackend::handleFstabChange(bool allowNotification)
+{
+ QStringList new_fstabIds;
+ KMountPoint::List fstab = KMountPoint::possibleMountPoints();
+
+ KMountPoint::List::iterator it = fstab.begin();
+ KMountPoint::List::iterator end = fstab.end();
+
+ for (; it!=end; ++it)
+ {
+ QString dev = (*it)->mountedFrom();
+ QString mp = (*it)->mountPoint();
+ QString fs = (*it)->mountType();
+
+ if ( ::inExclusionPattern(*it, m_networkSharesOnly) ) continue;
+
+ QString id = generateId(dev, mp);
+ new_fstabIds+=id;
+
+ if ( !m_fstabIds.contains(id) )
+ {
+ QString name = generateName(dev, fs);
+
+ Medium *m = new Medium(id, name);
+
+ m->mountableState(dev, mp, fs, false);
+
+ QString mime, icon, label;
+ guess(dev, mp, fs, false, mime, icon, label);
+
+ m->setMimeType(mime);
+ m->setIconName(icon);
+ m->setLabel(label);
+
+ m_mediaList.addMedium(m, allowNotification);
+ }
+ }
+
+ QStringList::iterator it2 = m_fstabIds.begin();
+ QStringList::iterator end2 = m_fstabIds.end();
+
+ for (; it2!=end2; ++it2)
+ {
+ if ( !new_fstabIds.contains(*it2) )
+ {
+ m_mediaList.removeMedium(*it2, allowNotification);
+ }
+ }
+
+ m_fstabIds = new_fstabIds;
+}
+
+QString FstabBackend::generateId(const QString &devNode,
+ const QString &mountPoint)
+{
+ QString d = KStandardDirs::realFilePath(devNode);
+ QString m = KStandardDirs::realPath(mountPoint);
+
+ return "/org/kde/mediamanager/fstab/"
+ +d.replace("/", "")
+ +m.replace("/", "");
+}
+
+QString FstabBackend::generateName(const QString &devNode, const QString &fsType)
+{
+ KURL url( devNode );
+
+ if ( url.isValid() )
+ {
+ return url.fileName();
+ }
+ else // surely something nfs or samba based
+ {
+ return fsType;
+ }
+}
+
+void FstabBackend::guess(const QString &devNode, const QString &mountPoint,
+ const QString &fsType, bool mounted,
+ QString &mimeType, QString &iconName, QString &label)
+{
+ enum { UNKNOWN, CD, CDWRITER, DVD, DVDWRITER } devType = UNKNOWN;
+#ifdef __linux__
+ // Guessing device types by mount point is not exactly accurate...
+ // Do something accurate first, and fall back if necessary.
+ int device=open(QFile::encodeName(devNode), O_RDONLY|O_NONBLOCK);
+ if(device>=0)
+ {
+ bool isCd=false;
+ QString devname=devNode.section('/', -1);
+ if(devname.startsWith("scd") || devname.startsWith("sr"))
+ {
+ // SCSI CD/DVD drive
+ isCd=true;
+ }
+ else if(devname.startsWith("hd"))
+ {
+ // IDE device -- we can't tell if this is a
+ // CD/DVD drive or harddisk by just looking at the
+ // filename
+ QFile m(QString("/proc/ide/") + devname + "/media");
+ if(m.open(IO_ReadOnly))
+ {
+ QString buf;
+ m.readLine(buf, 1024);
+ if(buf.contains("cdrom"))
+ isCd=true;
+ m.close();
+ }
+ }
+ if(isCd)
+ {
+ int drv=ioctl(device, CDROM_GET_CAPABILITY, CDSL_CURRENT);
+ if(drv>=0)
+ {
+ if((drv & CDC_DVD_R) || (drv & CDC_DVD_RAM))
+ devType = DVDWRITER;
+ else if((drv & CDC_CD_R) || (drv & CDC_CD_RW))
+ devType = CDWRITER;
+ else if(drv & CDC_DVD)
+ devType = DVD;
+ else
+ devType = CD;
+ }
+ }
+ close(device);
+ }
+#endif
+ if ( devType == CDWRITER
+ || devNode.find("cdwriter")!=-1 || mountPoint.find("cdwriter")!=-1
+ || devNode.find("cdrecorder")!=-1 || mountPoint.find("cdrecorder")!=-1
+ || devNode.find("cdburner")!=-1 || mountPoint.find("cdburner")!=-1
+ || devNode.find("cdrw")!=-1 || mountPoint.find("cdrw")!=-1
+ || devNode.find("graveur")!=-1
+ )
+ {
+ mimeType = "media/cdwriter";
+ label = i18n("CD Recorder");
+ }
+ else if ( devType == DVD || devType == DVDWRITER
+ || devNode.find("dvd")!=-1 || mountPoint.find("dvd")!=-1 )
+ {
+ mimeType = "media/dvd";
+ label = i18n("DVD");
+ }
+ else if ( devType == CD
+ || devNode.find("cdrom")!=-1 || mountPoint.find("cdrom")!=-1
+ // LINUX SPECIFIC
+ || devNode.find("/dev/scd")!=-1 || devNode.find("/dev/sr")!=-1
+ // FREEBSD SPECIFIC
+ || devNode.find("/acd")!=-1 || devNode.find("/scd")!=-1
+ )
+ {
+ mimeType = "media/cdrom";
+ label = i18n("CD-ROM");
+ }
+ else if ( devNode.find("fd")!=-1 || mountPoint.find("fd")!=-1
+ || devNode.find("floppy")!=-1 || mountPoint.find("floppy")!=-1 )
+ {
+ if ( devNode.find("360")!=-1 || devNode.find("1200")!=-1 )
+ {
+ mimeType = "media/floppy5";
+ }
+ else
+ {
+ mimeType = "media/floppy";
+ }
+ label = i18n("Floppy");
+ }
+ else if ( mountPoint.find("zip")!=-1
+ // FREEBSD SPECIFIC
+ || devNode.find("/afd")!=-1
+ )
+ {
+ mimeType = "media/zip";
+ label = i18n("Zip Disk");
+ }
+ else if ( mountPoint.find("removable")!=-1
+ || mountPoint.find("hotplug")!=-1
+ || mountPoint.find("usb")!=-1
+ || mountPoint.find("firewire")!=-1
+ || mountPoint.find("ieee1394")!=-1
+ || devNode.find("/usb/")!= -1
+ )
+ {
+ mimeType = "media/removable";
+ label = i18n("Removable Device");
+ }
+ else if ( fsType.find("nfs")!=-1 )
+ {
+ mimeType = "media/nfs";
+ label = i18n("Remote Share");
+ }
+ else if ( fsType.find("smb")!=-1 || fsType.find("cifs")!=-1
+ || devNode.find("//")!=-1 )
+ {
+ mimeType = "media/smb";
+ label = i18n("Remote Share");
+ }
+ else
+ {
+ mimeType = "media/hdd";
+ label = i18n("Hard Disk");
+ }
+
+ if ( mimeType=="media/nfs" || mimeType=="media/smb" )
+ {
+ label+= " (" + devNode + ")";
+ }
+ else
+ {
+ QString tmp = devNode;
+ if ( tmp.startsWith("/dev/") )
+ {
+ tmp = tmp.mid(5);
+ }
+ label+= " (" + tmp + ")";
+ }
+ mimeType+= (mounted ? "_mounted" : "_unmounted");
+ iconName = QString::null;
+}
+
+#include "fstabbackend.moc"
diff --git a/kioslave/media/mediamanager/fstabbackend.h b/kioslave/media/mediamanager/fstabbackend.h
new file mode 100644
index 000000000..ceb2f23ef
--- /dev/null
+++ b/kioslave/media/mediamanager/fstabbackend.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _FSTABBACKEND_H_
+#define _FSTABBACKEND_H_
+
+#include "backendbase.h"
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+#ifdef Q_OS_FREEBSD
+#include <qtimer.h>
+#endif
+
+class FstabBackend : public QObject, public BackendBase
+{
+Q_OBJECT
+
+public:
+ FstabBackend(MediaList &list, bool networkSharesOnly = false);
+ virtual ~FstabBackend();
+
+ static void guess(const QString &devNode, const QString &mountPoint,
+ const QString &fsType, bool mounted,
+ QString &mimeType, QString &iconName,
+ QString &label);
+
+ QString mount(const QString &id);
+ QString unmount(const QString &id);
+
+private slots:
+ void slotDirty(const QString &path);
+ void handleFstabChange(bool allowNotification = true);
+ void handleMtabChange(bool allowNotification = true);
+
+private:
+ static QString generateId(const QString &devNode,
+ const QString &mountPoint);
+ static QString generateName(const QString &devNode,
+ const QString &fsType);
+
+ bool m_networkSharesOnly;
+ QStringList m_mtabIds;
+ QMap<QString, QString> m_mtabEntries;
+ QStringList m_fstabIds;
+#ifdef Q_OS_FREEBSD
+ QTimer m_mtabTimer;
+#endif
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/halbackend.cpp b/kioslave/media/mediamanager/halbackend.cpp
new file mode 100644
index 000000000..65c796605
--- /dev/null
+++ b/kioslave/media/mediamanager/halbackend.cpp
@@ -0,0 +1,1345 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "halbackend.h"
+#include "linuxcdpolling.h"
+
+#include <stdlib.h>
+
+#include <kapplication.h>
+#include <qeventloop.h>
+#include <qfile.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <kprocess.h>
+#include <kconfig.h>
+#include <qstylesheet.h>
+#include <kmountpoint.h>
+#include <kmessagebox.h>
+#include <kio/job.h>
+
+#define MOUNT_SUFFIX (libhal_volume_is_mounted(halVolume) ? QString("_mounted") : QString("_unmounted"))
+#define MOUNT_ICON_SUFFIX (libhal_volume_is_mounted(halVolume) ? QString("_mount") : QString("_unmount"))
+
+/* Static instance of this class, for static HAL callbacks */
+static HALBackend* s_HALBackend;
+
+/* A macro function to convert HAL string properties to QString */
+QString libhal_device_get_property_QString(LibHalContext *ctx, const char* udi, const char *key)
+{
+ char* _ppt_string;
+ QString _ppt_QString;
+ DBusError error;
+ dbus_error_init(&error);
+ _ppt_string = libhal_device_get_property_string(ctx, udi, key, &error);
+ if ( _ppt_string )
+ _ppt_QString = _ppt_string;
+ libhal_free_string(_ppt_string);
+ return _ppt_QString;
+}
+
+/* Constructor */
+HALBackend::HALBackend(MediaList &list, QObject* parent)
+ : QObject()
+ , BackendBase(list)
+ , m_halContext(NULL)
+ , m_halStoragePolicy(NULL)
+ , m_parent(parent)
+{
+ s_HALBackend = this;
+}
+
+/* Destructor */
+HALBackend::~HALBackend()
+{
+ /* Close HAL connection */
+ if (m_halContext)
+ {
+ const QPtrList<Medium> medlist = m_mediaList.list();
+ QPtrListIterator<Medium> it (medlist);
+ for ( const Medium *current_medium = it.current(); current_medium; current_medium = ++it)
+ {
+ if( !current_medium->id().startsWith( "/org/kde" ))
+ unmount(current_medium->id());
+ }
+
+
+ /* Remove all the registered media first */
+ int numDevices;
+ char** halDeviceList = libhal_get_all_devices( m_halContext, &numDevices, NULL );
+
+ if ( halDeviceList )
+ {
+ for ( int i = 0; i < numDevices; i++ )
+ {
+ m_mediaList.removeMedium( halDeviceList[i], false );
+ }
+ }
+
+ libhal_free_string_array( halDeviceList );
+
+ DBusError error;
+ dbus_error_init(&error);
+ libhal_ctx_shutdown(m_halContext, &error);
+ libhal_ctx_free(m_halContext);
+ }
+
+ if (m_halStoragePolicy)
+ libhal_storage_policy_free(m_halStoragePolicy);
+}
+
+/* Connect to the HAL */
+bool HALBackend::InitHal()
+{
+ kdDebug(1219) << "Context new" << endl;
+ m_halContext = libhal_ctx_new();
+ if (!m_halContext)
+ {
+ kdDebug(1219) << "Failed to initialize HAL!" << endl;
+ return false;
+ }
+
+ // Main loop integration
+ kdDebug(1219) << "Main loop integration" << endl;
+ DBusError error;
+ dbus_error_init(&error);
+ dbus_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+
+ if (!dbus_connection || dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ libhal_ctx_free(m_halContext);
+ m_halContext = NULL;
+ return false;
+ }
+
+ dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+
+ MainLoopIntegration(dbus_connection);
+ libhal_ctx_set_dbus_connection(m_halContext, dbus_connection);
+
+ // HAL callback functions
+ kdDebug(1219) << "Callback functions" << endl;
+ libhal_ctx_set_device_added(m_halContext, HALBackend::hal_device_added);
+ libhal_ctx_set_device_removed(m_halContext, HALBackend::hal_device_removed);
+ libhal_ctx_set_device_new_capability (m_halContext, NULL);
+ libhal_ctx_set_device_lost_capability (m_halContext, NULL);
+ libhal_ctx_set_device_property_modified (m_halContext, HALBackend::hal_device_property_modified);
+ libhal_ctx_set_device_condition(m_halContext, HALBackend::hal_device_condition);
+
+ kdDebug(1219) << "Context Init" << endl;
+ if (!libhal_ctx_init(m_halContext, &error))
+ {
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+ libhal_ctx_free(m_halContext);
+ m_halContext = NULL;
+ kdDebug(1219) << "Failed to init HAL context!" << endl;
+ return false;
+ }
+
+ /** @todo customize watch policy */
+ kdDebug(1219) << "Watch properties" << endl;
+ if (!libhal_device_property_watch_all(m_halContext, &error))
+ {
+ kdDebug(1219) << "Failed to watch HAL properties!" << endl;
+ return false;
+ }
+
+ /* libhal-storage initialization */
+ kdDebug(1219) << "Storage Policy" << endl;
+ m_halStoragePolicy = libhal_storage_policy_new();
+ /** @todo define libhal-storage icon policy */
+
+ /* List devices at startup */
+ return ListDevices();
+}
+
+/* List devices (at startup)*/
+bool HALBackend::ListDevices()
+{
+ kdDebug(1219) << "ListDevices" << endl;
+
+ int numDevices;
+ char** halDeviceList = libhal_get_all_devices(m_halContext, &numDevices, NULL);
+
+ if (!halDeviceList)
+ return false;
+
+ kdDebug(1219) << "HALBackend::ListDevices : " << numDevices << " devices found" << endl;
+ for (int i = 0; i < numDevices; i++)
+ AddDevice(halDeviceList[i], false);
+
+ libhal_free_string_array( halDeviceList );
+
+ return true;
+}
+
+/* Create a media instance for the HAL device "udi".
+ This functions checks whether the device is worth listing */
+void HALBackend::AddDevice(const char *udi, bool allowNotification)
+{
+ /* We don't deal with devices that do not expose their capabilities.
+ If we don't check this, we will get a lot of warning messages from libhal */
+ if (!libhal_device_property_exists(m_halContext, udi, "info.capabilities", NULL))
+ return;
+
+ /* If the device is already listed, do not process.
+ This should not happen, but who knows... */
+ /** @todo : refresh properties instead ? */
+ if (m_mediaList.findById(udi))
+ return;
+
+ if (libhal_device_get_property_bool(m_halContext, "/org/freedesktop/Hal/devices/computer", "storage.disable_volume_handling", NULL))
+ allowNotification=false;
+
+ /* Add volume block devices */
+ if (libhal_device_query_capability(m_halContext, udi, "volume", NULL))
+ {
+ /* We only list volume that have a filesystem or volume that have an audio track*/
+ if ( libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") != "filesystem" &&
+ !libhal_device_get_property_bool(m_halContext, udi, "volume.disc.has_audio", NULL) &&
+ !libhal_device_get_property_bool(m_halContext, udi, "volume.disc.is_blank", NULL) )
+ return;
+
+ /* Query drive udi */
+ QString driveUdi = libhal_device_get_property_QString(m_halContext, udi, "block.storage_device");
+ if ( driveUdi.isNull() ) // no storage - no fun
+ return;
+
+ // if the device is locked do not act upon it
+ if (libhal_device_get_property_bool(m_halContext, driveUdi.ascii(), "info.locked", NULL))
+ allowNotification=false;
+
+ // if the device is locked do not act upon it
+ if (libhal_device_get_property_bool(m_halContext, driveUdi.ascii(), "storage.partition_table_changed", NULL))
+ allowNotification=false;
+
+ /** @todo check exclusion list **/
+
+ /* Create medium */
+ Medium* medium = new Medium(udi, "");
+ setVolumeProperties(medium);
+
+ if ( isInFstab( medium ).isNull() )
+ {
+ // if it's not mountable by user and not by HAL, don't show it at all
+ if ( ( libhal_device_get_property_QString(m_halContext, udi, "volume.fsusage") == "filesystem" &&
+ !libhal_device_get_property_bool(m_halContext, udi, "volume.is_mounted", NULL ) ) &&
+ ( libhal_device_get_property_bool(m_halContext, udi, "volume.ignore", NULL ) ) )
+ {
+ delete medium;
+ return;
+ }
+ }
+ QMap<QString,QString> options = MediaManagerUtils::splitOptions(mountoptions(udi));
+ kdDebug() << "automount " << options["automount"] << endl;
+ if (options["automount"] == "true" && allowNotification ) {
+ QString error = mount(medium);
+ if (!error.isEmpty())
+ kdDebug() << "error " << error << endl;
+ }
+ m_mediaList.addMedium(medium, allowNotification);
+
+ return;
+ }
+
+ /* Floppy & zip drives */
+ if (libhal_device_query_capability(m_halContext, udi, "storage", NULL))
+ if ((libhal_device_get_property_QString(m_halContext, udi, "storage.drive_type") == "floppy") ||
+ (libhal_device_get_property_QString(m_halContext, udi, "storage.drive_type") == "zip") ||
+ (libhal_device_get_property_QString(m_halContext, udi, "storage.drive_type") == "jaz"))
+ {
+ if (! libhal_device_get_property_bool(m_halContext, udi, "storage.removable.media_available", NULL) )
+ allowNotification = false;
+ /* Create medium */
+ Medium* medium = new Medium(udi, "");
+ // if the storage has a volume, we ignore it
+ if ( setFloppyProperties(medium) )
+ m_mediaList.addMedium(medium, allowNotification);
+ else
+ delete medium;
+ return;
+ }
+
+ /* Camera handled by gphoto2*/
+ if (libhal_device_query_capability(m_halContext, udi, "camera", NULL) &&
+ ((libhal_device_get_property_QString(m_halContext, udi, "camera.access_method")=="ptp") ||
+
+ (libhal_device_property_exists(m_halContext, udi, "camera.libgphoto2.support", NULL) &&
+ libhal_device_get_property_bool(m_halContext, udi, "camera.libgphoto2.support", NULL)))
+ )
+ {
+ /* Create medium */
+ Medium* medium = new Medium(udi, "");
+ setCameraProperties(medium);
+ m_mediaList.addMedium(medium, allowNotification);
+ return;
+ }
+}
+
+void HALBackend::RemoveDevice(const char *udi)
+{
+ m_mediaList.removeMedium(udi, true);
+}
+
+void HALBackend::ModifyDevice(const char *udi, const char* key)
+{
+ const char* mediumUdi = findMediumUdiFromUdi(udi);
+ if (!mediumUdi)
+ return;
+ bool allowNotification = false;
+ if (strcmp(key, "storage.removable.media_available") == 0)
+ allowNotification = libhal_device_get_property_bool(m_halContext, udi, key, NULL);
+ ResetProperties(mediumUdi, allowNotification);
+}
+
+void HALBackend::DeviceCondition(const char* udi, const char* condition)
+{
+ QString conditionName = QString(condition);
+ kdDebug(1219) << "Processing device condition " << conditionName << " for " << udi << endl;
+
+ if (conditionName == "EjectPressed") {
+ const Medium* medium = m_mediaList.findById(udi);
+ if (!medium) {
+ /* the ejectpressed appears on the drive and we need to find the volume */
+ const QPtrList<Medium> medlist = m_mediaList.list();
+ QPtrListIterator<Medium> it (medlist);
+ for ( const Medium *current_medium = it.current(); current_medium; current_medium = ++it)
+ {
+ if( current_medium->id().startsWith( "/org/kde" ))
+ continue;
+ QString driveUdi = libhal_device_get_property_QString(m_halContext, current_medium->id().latin1(), "block.storage_device");
+ if (driveUdi == udi)
+ {
+ medium = current_medium;
+ break;
+ }
+ }
+ }
+ if (medium) {
+ KProcess p;
+ p << "kio_media_mounthelper" << "-e" << medium->name();
+ p.start(KProcess::DontCare);
+ }
+ }
+
+ const char* mediumUdi = findMediumUdiFromUdi(udi);
+ kdDebug() << "findMedumUdiFromUdi " << udi << " returned " << mediumUdi << endl;
+ if (!mediumUdi)
+ return;
+
+ /* TODO: Warn the user that (s)he should unmount devices before unplugging */
+ if (conditionName == "VolumeUnmountForced")
+ ResetProperties(mediumUdi);
+
+ /* Reset properties after mounting */
+ if (conditionName == "VolumeMount")
+ ResetProperties(mediumUdi);
+
+ /* Reset properties after unmounting */
+ if (conditionName == "VolumeUnmount")
+ ResetProperties(mediumUdi);
+
+}
+
+void HALBackend::MainLoopIntegration(DBusConnection *dbusConnection)
+{
+ m_dBusQtConnection = new DBusQt::Connection(m_parent);
+ m_dBusQtConnection->dbus_connection_setup_with_qt_main(dbusConnection);
+}
+
+/******************************************
+ ** Properties attribution **
+ ******************************************/
+
+/* Return the medium udi that should be updated when recieving a call for
+ device udi */
+const char* HALBackend::findMediumUdiFromUdi(const char* udi)
+{
+ /* Easy part : this Udi is already registered as a device */
+ const Medium* medium = m_mediaList.findById(udi);
+ if (medium)
+ return medium->id().ascii();
+
+ /* Hard part : this is a volume whose drive is registered */
+ if (libhal_device_property_exists(m_halContext, udi, "info.capabilities", NULL))
+ if (libhal_device_query_capability(m_halContext, udi, "volume", NULL))
+ {
+ QString driveUdi = libhal_device_get_property_QString(m_halContext, udi, "block.storage_device");
+ return findMediumUdiFromUdi(driveUdi.ascii());
+ }
+
+ return NULL;
+}
+
+void HALBackend::ResetProperties(const char* mediumUdi, bool allowNotification)
+{
+ kdDebug(1219) << "HALBackend::setProperties" << endl;
+ if ( QString::fromLatin1( mediumUdi ).startsWith( "/org/kde/" ) )
+ {
+ const Medium *cmedium = m_mediaList.findById(mediumUdi);
+ if ( cmedium )
+ {
+ Medium m( *cmedium );
+ if ( setFstabProperties( &m ) ) {
+ kdDebug() << "setFstabProperties worked" << endl;
+ m_mediaList.changeMediumState(m, allowNotification);
+ }
+ return;
+ }
+ }
+
+ Medium* m = new Medium(mediumUdi, "");
+
+ if (libhal_device_query_capability(m_halContext, mediumUdi, "volume", NULL))
+ setVolumeProperties(m);
+ if (libhal_device_query_capability(m_halContext, mediumUdi, "storage", NULL))
+ setFloppyProperties(m);
+ if (libhal_device_query_capability(m_halContext, mediumUdi, "camera", NULL))
+ setCameraProperties(m);
+
+ m_mediaList.changeMediumState(*m, allowNotification);
+
+ delete m;
+}
+
+void HALBackend::setVolumeProperties(Medium* medium)
+{
+ kdDebug(1219) << "HALBackend::setVolumeProperties for " << medium->id() << endl;
+
+ const char* udi = medium->id().ascii();
+ /* Check if the device still exists */
+ if (!libhal_device_exists(m_halContext, udi, NULL))
+ return;
+
+ /* Get device information from libhal-storage */
+ LibHalVolume* halVolume = libhal_volume_from_udi(m_halContext, udi);
+ if (!halVolume)
+ return;
+ QString driveUdi = libhal_volume_get_storage_device_udi(halVolume);
+ LibHalDrive* halDrive = 0;
+ if ( !driveUdi.isNull() )
+ halDrive = libhal_drive_from_udi(m_halContext, driveUdi.ascii());
+ if (!halDrive) {
+ // at times HAL sends an UnmountForced event before the device is removed
+ libhal_volume_free(halVolume);
+ return;
+ }
+
+ medium->setName(
+ generateName(libhal_volume_get_device_file(halVolume)) );
+
+ medium->mountableState(
+ libhal_volume_get_device_file(halVolume), /* Device node */
+ libhal_volume_get_mount_point(halVolume), /* Mount point */
+ libhal_volume_get_fstype(halVolume), /* Filesystem type */
+ libhal_volume_is_mounted(halVolume) ); /* Mounted ? */
+
+ char* name = libhal_volume_policy_compute_display_name(halDrive, halVolume, m_halStoragePolicy);
+ QString volume_name = QString::fromUtf8(name);
+ QString media_name = volume_name;
+ medium->setLabel(media_name);
+ free(name);
+
+ QString mimeType;
+ if (libhal_volume_is_disc(halVolume))
+ {
+ mimeType = "media/cdrom" + MOUNT_SUFFIX;
+
+ LibHalVolumeDiscType discType = libhal_volume_get_disc_type(halVolume);
+ if ((discType == LIBHAL_VOLUME_DISC_TYPE_CDROM) ||
+ (discType == LIBHAL_VOLUME_DISC_TYPE_CDR) ||
+ (discType == LIBHAL_VOLUME_DISC_TYPE_CDRW))
+ if (libhal_volume_disc_is_blank(halVolume))
+ {
+ mimeType = "media/blankcd";
+ medium->unmountableState("");
+ }
+ else
+ mimeType = "media/cdwriter" + MOUNT_SUFFIX;
+
+ if ((discType == LIBHAL_VOLUME_DISC_TYPE_DVDROM) || (discType == LIBHAL_VOLUME_DISC_TYPE_DVDRAM) ||
+ (discType == LIBHAL_VOLUME_DISC_TYPE_DVDR) || (discType == LIBHAL_VOLUME_DISC_TYPE_DVDRW) ||
+ (discType == LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR) || (discType == LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW) )
+ if (libhal_volume_disc_is_blank(halVolume))
+ {
+ mimeType = "media/blankdvd";
+ medium->unmountableState("");
+ }
+ else
+ mimeType = "media/dvd" + MOUNT_SUFFIX;
+
+ if (libhal_volume_disc_has_audio(halVolume) && !libhal_volume_disc_has_data(halVolume))
+ {
+ mimeType = "media/audiocd";
+ medium->unmountableState( "audiocd:/?device=" + QString(libhal_volume_get_device_file(halVolume)) );
+ }
+
+ medium->setIconName(QString::null);
+
+ /* check if the disc id a vcd or a video dvd */
+ DiscType type = LinuxCDPolling::identifyDiscType(libhal_volume_get_device_file(halVolume));
+ switch (type)
+ {
+ case DiscType::VCD:
+ mimeType = "media/vcd";
+ break;
+ case DiscType::SVCD:
+ mimeType = "media/svcd";
+ break;
+ case DiscType::DVD:
+ mimeType = "media/dvdvideo";
+ break;
+ }
+ }
+ else
+ {
+ mimeType = "media/hdd" + MOUNT_SUFFIX;
+ medium->setIconName(QString::null); // reset icon
+ if (libhal_drive_is_hotpluggable(halDrive))
+ {
+ mimeType = "media/removable" + MOUNT_SUFFIX;
+ medium->needMounting();
+ switch (libhal_drive_get_type(halDrive)) {
+ case LIBHAL_DRIVE_TYPE_COMPACT_FLASH:
+ medium->setIconName("compact_flash" + MOUNT_ICON_SUFFIX);
+ break;
+ case LIBHAL_DRIVE_TYPE_MEMORY_STICK:
+ medium->setIconName("memory_stick" + MOUNT_ICON_SUFFIX);
+ break;
+ case LIBHAL_DRIVE_TYPE_SMART_MEDIA:
+ medium->setIconName("smart_media" + MOUNT_ICON_SUFFIX);
+ break;
+ case LIBHAL_DRIVE_TYPE_SD_MMC:
+ medium->setIconName("sd_mmc" + MOUNT_ICON_SUFFIX);
+ break;
+ case LIBHAL_DRIVE_TYPE_PORTABLE_AUDIO_PLAYER:
+ {
+ medium->setIconName("ipod" + MOUNT_ICON_SUFFIX);
+ break;
+ }
+ case LIBHAL_DRIVE_TYPE_CAMERA:
+ {
+ mimeType = "media/camera" + MOUNT_SUFFIX;
+ const char *physdev = libhal_drive_get_physical_device_udi(halDrive);
+ // get model from camera
+ if (physdev && libhal_device_query_capability(m_halContext, physdev, "camera", NULL))
+ {
+ if (libhal_device_property_exists(m_halContext, physdev, "usb_device.product", NULL))
+ medium->setLabel(libhal_device_get_property_QString(m_halContext, physdev, "usb_device.product"));
+ else if (libhal_device_property_exists(m_halContext, physdev, "usb.product", NULL))
+ medium->setLabel(libhal_device_get_property_QString(m_halContext, physdev, "usb.product"));
+ }
+ break;
+ }
+ case LIBHAL_DRIVE_TYPE_TAPE:
+ medium->setIconName(QString::null); //FIXME need icon
+ break;
+ default:
+ medium->setIconName(QString::null);
+ }
+
+ if (medium->isMounted() && QFile::exists(medium->mountPoint() + "/dcim"))
+ {
+ mimeType = "media/camera" + MOUNT_SUFFIX;
+ }
+ }
+ }
+ medium->setMimeType(mimeType);
+
+ libhal_drive_free(halDrive);
+ libhal_volume_free(halVolume);
+}
+
+bool HALBackend::setFstabProperties( Medium *medium )
+{
+ QString mp = isInFstab(medium);
+
+ if (!mp.isNull() && !medium->id().startsWith( "/org/kde" ) )
+ {
+ // now that we know it's in fstab, we have to find out if it's mounted
+ KMountPoint::List mtab = KMountPoint::currentMountPoints();
+
+ KMountPoint::List::iterator it = mtab.begin();
+ KMountPoint::List::iterator end = mtab.end();
+
+ bool mounted = false;
+
+ for (; it!=end; ++it)
+ {
+ if ((*it)->mountedFrom() == medium->deviceNode() && (*it)->mountPoint() == mp )
+ {
+ mounted = true;
+ break;
+ }
+ }
+
+ kdDebug() << mp << " " << mounted << " " << medium->deviceNode() << " " << endl;
+ QString fstype = medium->fsType();
+ if ( fstype.isNull() )
+ fstype = "auto";
+
+ medium->mountableState(
+ medium->deviceNode(),
+ mp, /* Mount point */
+ fstype, /* Filesystem type */
+ mounted ); /* Mounted ? */
+
+ return true;
+ }
+
+ return false;
+
+}
+
+// Handle floppies and zip drives
+bool HALBackend::setFloppyProperties(Medium* medium)
+{
+ kdDebug(1219) << "HALBackend::setFloppyProperties for " << medium->id() << endl;
+
+ const char* udi = medium->id().ascii();
+ /* Check if the device still exists */
+ if (!libhal_device_exists(m_halContext, udi, NULL))
+ return false;
+
+ LibHalDrive* halDrive = libhal_drive_from_udi(m_halContext, udi);
+ if (!halDrive)
+ return false;
+
+ QString drive_type = libhal_device_get_property_QString(m_halContext, udi, "storage.drive_type");
+
+ if (drive_type == "zip") {
+ int numVolumes;
+ char** volumes = libhal_drive_find_all_volumes(m_halContext, halDrive, &numVolumes);
+ libhal_free_string_array(volumes);
+ kdDebug(1219) << " found " << numVolumes << " volumes" << endl;
+ if (numVolumes)
+ {
+ libhal_drive_free(halDrive);
+ return false;
+ }
+ }
+
+ medium->setName( generateName(libhal_drive_get_device_file(halDrive)) );
+ medium->setLabel(i18n("Unknown Drive"));
+
+ // HAL hates floppies - so we have to do it twice ;(
+ medium->mountableState(libhal_drive_get_device_file(halDrive), QString::null, QString::null, false);
+ setFloppyMountState(medium);
+
+ if (drive_type == "floppy")
+ {
+ if (medium->isMounted()) // don't use _SUFFIX here as it accesses the volume
+ medium->setMimeType("media/floppy_mounted" );
+ else
+ medium->setMimeType("media/floppy_unmounted");
+ medium->setLabel(i18n("Floppy Drive"));
+ }
+ else if (drive_type == "zip")
+ {
+ if (medium->isMounted())
+ medium->setMimeType("media/zip_mounted" );
+ else
+ medium->setMimeType("media/zip_unmounted");
+ medium->setLabel(i18n("Zip Drive"));
+ }
+
+ /** @todo And mimtype for JAZ drives ? */
+
+ medium->setIconName(QString::null);
+
+ libhal_drive_free(halDrive);
+
+ return true;
+}
+
+void HALBackend::setFloppyMountState( Medium *medium )
+{
+ if ( !medium->id().startsWith( "/org/kde" ) )
+ {
+ KMountPoint::List mtab = KMountPoint::currentMountPoints();
+ KMountPoint::List::iterator it = mtab.begin();
+ KMountPoint::List::iterator end = mtab.end();
+
+ QString fstype;
+ QString mountpoint;
+ for (; it!=end; ++it)
+ {
+ if ((*it)->mountedFrom() == medium->deviceNode() )
+ {
+ fstype = (*it)->mountType().isNull() ? (*it)->mountType() : "auto";
+ mountpoint = (*it)->mountPoint();
+ medium->mountableState( medium->deviceNode(), mountpoint, fstype, true );
+ return;
+ }
+ }
+ }
+}
+
+void HALBackend::setCameraProperties(Medium* medium)
+{
+ kdDebug(1219) << "HALBackend::setCameraProperties for " << medium->id() << endl;
+
+ const char* udi = medium->id().ascii();
+ /* Check if the device still exists */
+ if (!libhal_device_exists(m_halContext, udi, NULL))
+ return;
+
+ /** @todo find name */
+ medium->setName("camera");
+
+ QString device = "camera:/";
+
+ char *cam = libhal_device_get_property_string(m_halContext, udi, "camera.libgphoto2.name", NULL);
+ DBusError error;
+ dbus_error_init(&error);
+ if (cam &&
+ libhal_device_property_exists(m_halContext, udi, "usb.linux.device_number", NULL) &&
+ libhal_device_property_exists(m_halContext, udi, "usb.bus_number", NULL))
+ device.sprintf("camera://%s@[usb:%03d,%03d]/", cam,
+ libhal_device_get_property_int(m_halContext, udi, "usb.bus_number", &error),
+ libhal_device_get_property_int(m_halContext, udi, "usb.linux.device_number", &error));
+
+ libhal_free_string(cam);
+
+ /** @todo find the rest of this URL */
+ medium->unmountableState(device);
+ medium->setMimeType("media/gphoto2camera");
+ medium->setIconName(QString::null);
+ if (libhal_device_property_exists(m_halContext, udi, "usb_device.product", NULL))
+ medium->setLabel(libhal_device_get_property_QString(m_halContext, udi, "usb_device.product"));
+ else if (libhal_device_property_exists(m_halContext, udi, "usb.product", NULL))
+ medium->setLabel(libhal_device_get_property_QString(m_halContext, udi, "usb.product"));
+ else
+ medium->setLabel(i18n("Camera"));
+}
+
+QString HALBackend::generateName(const QString &devNode)
+{
+ return KURL(devNode).fileName();
+}
+
+/******************************************
+ ** HAL CALL-BACKS **
+ ******************************************/
+
+void HALBackend::hal_device_added(LibHalContext *ctx, const char *udi)
+{
+ kdDebug(1219) << "HALBackend::hal_device_added " << udi << endl;
+ Q_UNUSED(ctx);
+ s_HALBackend->AddDevice(udi);
+}
+
+void HALBackend::hal_device_removed(LibHalContext *ctx, const char *udi)
+{
+ kdDebug(1219) << "HALBackend::hal_device_removed " << udi << endl;
+ Q_UNUSED(ctx);
+ s_HALBackend->RemoveDevice(udi);
+}
+
+void HALBackend::hal_device_property_modified(LibHalContext *ctx, const char *udi,
+ const char *key, dbus_bool_t is_removed, dbus_bool_t is_added)
+{
+ kdDebug(1219) << "HALBackend::hal_property_modified " << udi << " -- " << key << endl;
+ Q_UNUSED(ctx);
+ Q_UNUSED(is_removed);
+ Q_UNUSED(is_added);
+ s_HALBackend->ModifyDevice(udi, key);
+}
+
+void HALBackend::hal_device_condition(LibHalContext *ctx, const char *udi,
+ const char *condition_name,
+ const char* message
+ )
+{
+ kdDebug(1219) << "HALBackend::hal_device_condition " << udi << " -- " << condition_name << endl;
+ Q_UNUSED(ctx);
+ Q_UNUSED(message);
+ s_HALBackend->DeviceCondition(udi, condition_name);
+}
+
+QStringList HALBackend::mountoptions(const QString &name)
+{
+ const Medium* medium = m_mediaList.findById(name);
+ if (medium && !isInFstab(medium).isNull())
+ return QStringList(); // not handled by HAL - fstab entry
+
+ KConfig config("mediamanagerrc");
+ config.setGroup(name);
+
+ char ** array = libhal_device_get_property_strlist(m_halContext, name.latin1(), "volume.mount.valid_options", NULL);
+ QMap<QString,bool> valids;
+
+ for (int index = 0; array && array[index]; ++index) {
+ QString t = array[index];
+ if (t.endsWith("="))
+ t = t.left(t.length() - 1);
+ valids[t] = true;
+ kdDebug() << "valid " << t << endl;
+ }
+ libhal_free_string_array(array);
+ QStringList result;
+ QString tmp;
+
+ QString fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.fstype");
+ if (fstype.isNull())
+ fstype = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.mount_filesystem");
+
+ QString drive_udi = libhal_device_get_property_QString(m_halContext, name.latin1(), "block.storage_device");
+
+ bool removable = false;
+ if ( !drive_udi.isNull() )
+ removable = libhal_device_get_property_bool(m_halContext, drive_udi.latin1(), "storage.removable", NULL)
+ || libhal_device_get_property_bool(m_halContext, drive_udi.latin1(), "storage.hotpluggable", NULL);
+
+ config.setGroup(drive_udi);
+ bool value = config.readBoolEntry("automount", false);
+ config.setGroup(name);
+
+ if (libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_blank", NULL)
+ || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_vcd", NULL)
+ || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_svcd", NULL)
+ || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.is_videodvd", NULL)
+ || libhal_device_get_property_bool(m_halContext, name.latin1(), "volume.disc.has_audio", NULL))
+ value = false;
+
+ result << QString("automount=%1").arg(value ? "true" : "false");
+
+ if (valids.contains("ro"))
+ {
+ value = config.readBoolEntry("ro", false);
+ tmp = QString("ro=%1").arg(value ? "true" : "false");
+ if (fstype != "iso9660") // makes no sense
+ result << tmp;
+ }
+
+ if (valids.contains("quiet"))
+ {
+ value = config.readBoolEntry("quiet", false);
+ tmp = QString("quiet=%1").arg(value ? "true" : "false");
+ if (fstype != "iso9660") // makes no sense
+ result << tmp;
+ }
+
+ if (valids.contains("flush"))
+ {
+ value = config.readBoolEntry("flush", fstype.endsWith("fat"));
+ tmp = QString("flush=%1").arg(value ? "true" : "false");
+ result << tmp;
+ }
+
+ if (valids.contains("uid"))
+ {
+ value = config.readBoolEntry("uid", true);
+ tmp = QString("uid=%1").arg(value ? "true" : "false");
+ result << tmp;
+ }
+
+ if (valids.contains("utf8"))
+ {
+ value = config.readBoolEntry("utf8", true);
+ tmp = QString("utf8=%1").arg(value ? "true" : "false");
+ result << tmp;
+ }
+
+ if (valids.contains("shortname"))
+ {
+ QString svalue = config.readEntry("shortname", "lower").lower();
+ if (svalue == "winnt")
+ result << "shortname=winnt";
+ else if (svalue == "win95")
+ result << "shortname=win95";
+ else if (svalue == "mixed")
+ result << "shortname=mixed";
+ else
+ result << "shortname=lower";
+ }
+
+ // pass our locale to the ntfs-3g driver so it can translate local characters
+ if (valids.contains("locale") && fstype == "ntfs-3g")
+ {
+ // have to obtain LC_CTYPE as returned by the `locale` command
+ // check in the same order as `locale` does
+ char *cType;
+ if ( (cType = getenv("LC_ALL")) || (cType = getenv("LC_CTYPE")) || (cType = getenv("LANG")) ) {
+ result << QString("locale=%1").arg(cType);
+ }
+ }
+
+ if (valids.contains("sync"))
+ {
+ value = config.readBoolEntry("sync", ( valids.contains("flush") && !fstype.endsWith("fat") ) && removable);
+ tmp = QString("sync=%1").arg(value ? "true" : "false");
+ if (fstype != "iso9660") // makes no sense
+ result << tmp;
+ }
+
+ if (valids.contains("noatime"))
+ {
+ value = config.readBoolEntry("atime", !fstype.endsWith("fat"));
+ tmp = QString("atime=%1").arg(value ? "true" : "false");
+ if (fstype != "iso9660") // makes no sense
+ result << tmp;
+ }
+
+ QString mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.mount_point");
+ if (mount_point.isEmpty())
+ mount_point = libhal_device_get_property_QString(m_halContext, name.latin1(), "volume.policy.desired_mount_point");
+
+ mount_point = config.readEntry("mountpoint", mount_point);
+
+ if (!mount_point.startsWith("/"))
+ mount_point = "/media/" + mount_point;
+
+ result << QString("mountpoint=%1").arg(mount_point);
+ result << QString("filesystem=%1").arg(fstype);
+
+ if (valids.contains("data"))
+ {
+ QString svalue = config.readEntry("journaling").lower();
+ if (svalue == "ordered")
+ result << "journaling=ordered";
+ else if (svalue == "writeback")
+ result << "journaling=writeback";
+ else if (svalue == "data")
+ result << "journaling=data";
+ else
+ result << "journaling=ordered";
+ }
+
+ return result;
+}
+
+bool HALBackend::setMountoptions(const QString &name, const QStringList &options )
+{
+ kdDebug() << "setMountoptions " << name << " " << options << endl;
+
+ KConfig config("mediamanagerrc");
+ config.setGroup(name);
+
+ QMap<QString,QString> valids = MediaManagerUtils::splitOptions(options);
+
+ const char *names[] = { "ro", "quiet", "atime", "uid", "utf8", "flush", "sync", 0 };
+ for (int index = 0; names[index]; ++index)
+ if (valids.contains(names[index]))
+ config.writeEntry(names[index], valids[names[index]] == "true");
+
+ if (valids.contains("shortname"))
+ config.writeEntry("shortname", valids["shortname"]);
+
+ if (valids.contains("journaling"))
+ config.writeEntry("journaling", valids["journaling"]);
+
+ if (!mountoptions(name).contains(QString("mountpoint=%1").arg(valids["mountpoint"])))
+ config.writeEntry("mountpoint", valids["mountpoint"]);
+
+ if (valids.contains("automount")) {
+ QString drive_udi = libhal_device_get_property_QString(m_halContext, name.latin1(), "block.storage_device");
+ config.setGroup(drive_udi);
+ config.writeEntry("automount", valids["automount"]);
+ }
+
+ return true;
+}
+
+static QString mount_priv(const char *udi, const char *mount_point, const char **poptions, int noptions,
+ DBusConnection *dbus_connection)
+{
+ DBusMessage *dmesg, *reply;
+ DBusError error;
+
+ const char *fstype = "";
+ if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume",
+ "Mount"))) {
+ kdDebug() << "mount failed for " << udi << ": could not create dbus message\n";
+ return i18n("Internal Error");
+ }
+
+ if (!dbus_message_append_args (dmesg, DBUS_TYPE_STRING, &mount_point, DBUS_TYPE_STRING, &fstype,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &poptions, noptions,
+ DBUS_TYPE_INVALID))
+ {
+ kdDebug() << "mount failed for " << udi << ": could not append args to dbus message\n";
+ dbus_message_unref (dmesg);
+ return i18n("Internal Error");
+ }
+
+ QString qerror;
+
+ dbus_error_init (&error);
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error)))
+ {
+ QString qerror = error.message;
+ kdError() << "mount failed for " << udi << ": " << error.name << " - " << qerror << endl;
+ if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType"))
+ qerror = i18n("Invalid filesystem type");
+ else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDenied"))
+ qerror = i18n("Permissions denied");
+ else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.AlreadyMounted"))
+ qerror = i18n("Device is already mounted.");
+ else if ( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint") && strlen(mount_point)) {
+ dbus_message_unref (dmesg);
+ dbus_error_free (&error);
+ return mount_priv(udi, "", poptions, noptions, dbus_connection);
+ }
+ dbus_message_unref (dmesg);
+ dbus_error_free (&error);
+ return qerror;
+ }
+
+ kdDebug() << "mount queued for " << udi << endl;
+
+ dbus_message_unref (dmesg);
+ dbus_message_unref (reply);
+
+ return qerror;
+
+}
+
+QString HALBackend::listUsingProcesses(const Medium* medium)
+{
+ QString proclist, fullmsg;
+ QString cmdline = QString("/usr/bin/env fuser -vm %1 2>&1").arg(KProcess::quote(medium->mountPoint()));
+ FILE *fuser = popen(cmdline.latin1(), "r");
+
+ uint counter = 0;
+ if (fuser) {
+ proclist += "<pre>";
+ QTextIStream is(fuser);
+ QString tmp;
+ while (!is.atEnd()) {
+ tmp = is.readLine();
+ tmp = QStyleSheet::escape(tmp) + "\n";
+
+ proclist += tmp;
+ if (counter++ > 10)
+ {
+ proclist += "...";
+ break;
+ }
+ }
+ proclist += "</pre>";
+ (void)pclose( fuser );
+ }
+ if (counter) {
+ fullmsg = i18n("Moreover, programs still using the device "
+ "have been detected. They are listed below. You have to "
+ "close them or change their working directory before "
+ "attempting to unmount the device again.");
+ fullmsg += "<br>" + proclist;
+ return fullmsg;
+ } else {
+ return QString::null;
+ }
+}
+
+void HALBackend::slotResult(KIO::Job *job)
+{
+ kdDebug() << "slotResult " << mount_jobs[job] << endl;
+
+ struct mount_job_data *data = mount_jobs[job];
+ QString& qerror = data->errorMessage;
+ const Medium* medium = data->medium;
+
+ if (job->error() == KIO::ERR_COULD_NOT_UNMOUNT) {
+ QString proclist(listUsingProcesses(medium));
+
+ qerror = "<qt>";
+ qerror += "<p>" + i18n("Unfortunately, the device <b>%1</b> (%2) named <b>'%3'</b> and "
+ "currently mounted at <b>%4</b> could not be unmounted. ").arg(
+ "system:/media/" + medium->name(),
+ medium->deviceNode(),
+ medium->prettyLabel(),
+ medium->prettyBaseURL().pathOrURL()) + "</p>";
+ qerror += "<p>" + i18n("The following error was returned by umount command:");
+ qerror += "</p><pre>" + job->errorText() + "</pre>";
+
+ if (!proclist.isEmpty()) {
+ qerror += proclist;
+ }
+ qerror += "</qt>";
+ } else if (job->error()) {
+ qerror = job->errorText();
+ }
+
+ ResetProperties( medium->id().latin1() );
+ mount_jobs.remove(job);
+
+ /* Job completed. Notify the caller */
+ data->error = job->error();
+ data->completed = true;
+ kapp->eventLoop()->exitLoop();
+}
+
+QString HALBackend::isInFstab(const Medium *medium)
+{
+ KMountPoint::List fstab = KMountPoint::possibleMountPoints(KMountPoint::NeedMountOptions|KMountPoint::NeedRealDeviceName);
+
+ KMountPoint::List::iterator it = fstab.begin();
+ KMountPoint::List::iterator end = fstab.end();
+
+ for (; it!=end; ++it)
+ {
+ QString reald = (*it)->realDeviceName();
+ if ( reald.endsWith( "/" ) )
+ reald = reald.left( reald.length() - 1 );
+ kdDebug() << "isInFstab -" << medium->deviceNode() << "- -" << reald << "- -" << (*it)->mountedFrom() << "-" << endl;
+ if ((*it)->mountedFrom() == medium->deviceNode() || ( !medium->deviceNode().isEmpty() && reald == medium->deviceNode() ) )
+ {
+ QStringList opts = (*it)->mountOptions();
+ if (opts.contains("user") || opts.contains("users"))
+ return (*it)->mountPoint();
+ }
+ }
+
+ return QString::null;
+}
+
+QString HALBackend::mount(const Medium *medium)
+{
+ if (medium->isMounted())
+ return QString(); // that was easy
+
+ QString mountPoint = isInFstab(medium);
+ if (!mountPoint.isNull())
+ {
+ struct mount_job_data data;
+ data.completed = false;
+ data.medium = medium;
+
+ kdDebug() << "triggering user mount " << medium->deviceNode() << " " << mountPoint << " " << medium->id() << endl;
+ KIO::Job *job = KIO::mount( false, 0, medium->deviceNode(), mountPoint );
+ connect(job, SIGNAL( result (KIO::Job *)),
+ SLOT( slotResult( KIO::Job *)));
+ mount_jobs[job] = &data;
+ // The caller expects the device to be mounted when the function
+ // completes. Thus block until the job completes.
+ while (!data.completed) {
+ kapp->eventLoop()->enterLoop();
+ }
+ // Return the error message (if any) to the caller
+ return (data.error) ? data.errorMessage : QString::null;
+
+ } else if (medium->id().startsWith("/org/kde/") )
+ return i18n("Permissions denied");
+
+ QStringList soptions;
+
+ kdDebug() << "mounting " << medium->id() << "..." << endl;
+
+ QMap<QString,QString> valids = MediaManagerUtils::splitOptions(mountoptions(medium->id()));
+ if (valids["flush"] == "true")
+ soptions << "flush";
+
+ if (valids["uid"] == "true")
+ {
+ soptions << QString("uid=%1").arg(getuid());
+ }
+
+ if (valids["ro"] == "true")
+ soptions << "ro";
+
+ if (valids["atime"] != "true")
+ soptions << "noatime";
+
+ if (valids["quiet"] == "true")
+ soptions << "quiet";
+
+ if (valids["utf8"] == "true")
+ soptions << "utf8";
+
+ if (valids["sync"] == "true")
+ soptions << "sync";
+
+ QString mount_point = valids["mountpoint"];
+ if (mount_point.startsWith("/media/"))
+ mount_point = mount_point.mid(7);
+
+ if (valids.contains("shortname"))
+ {
+ soptions << QString("shortname=%1").arg(valids["shortname"]);
+ }
+
+ if (valids.contains("locale"))
+ {
+ soptions << QString("locale=%1").arg(valids["locale"]);
+ }
+
+ if (valids.contains("journaling"))
+ {
+ QString option = valids["journaling"];
+ if (option == "data")
+ soptions << QString("data=journal");
+ else if (option == "writeback")
+ soptions << QString("data=writeback");
+ else
+ soptions << QString("data=ordered");
+ }
+
+ const char **options = new const char*[soptions.size() + 1];
+ uint noptions = 0;
+ for (QStringList::ConstIterator it = soptions.begin(); it != soptions.end(); ++it, ++noptions)
+ options[noptions] = (*it).latin1();
+ options[noptions] = NULL;
+
+ QString qerror = mount_priv(medium->id().latin1(), mount_point.utf8(), options, noptions, dbus_connection);
+ if (!qerror.isEmpty()) {
+ kdError() << "mounting " << medium->id() << " returned " << qerror << endl;
+ return qerror;
+ }
+
+ medium->setHalMounted(true);
+ ResetProperties(medium->id().latin1());
+
+ return QString();
+}
+
+QString HALBackend::mount(const QString &_udi)
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ return i18n("No such medium: %1").arg(_udi);
+
+ return mount(medium);
+}
+
+QString HALBackend::unmount(const QString &_udi)
+{
+ const Medium* medium = m_mediaList.findById(_udi);
+ if (!medium)
+ { // now we get fancy: if the udi is no volume, it _might_ be a device with only one
+ // volume on it (think CDs) - so we're so nice to the caller to unmount that volume
+ LibHalDrive* halDrive = libhal_drive_from_udi(m_halContext, _udi.latin1());
+ if (halDrive)
+ {
+ int numVolumes;
+ char** volumes = libhal_drive_find_all_volumes(m_halContext, halDrive, &numVolumes);
+ if (numVolumes == 1)
+ medium = m_mediaList.findById( volumes[0] );
+ }
+ }
+
+ if ( !medium )
+ return i18n("No such medium: %1").arg(_udi);
+
+ if (!medium->isMounted())
+ return QString(); // that was easy
+
+ QString mountPoint = isInFstab(medium);
+ if (!mountPoint.isNull())
+ {
+ struct mount_job_data data;
+ data.completed = false;
+ data.medium = medium;
+
+ kdDebug() << "triggering user unmount " << medium->deviceNode() << " " << mountPoint << endl;
+ KIO::Job *job = KIO::unmount( medium->mountPoint(), false );
+ connect(job, SIGNAL( result (KIO::Job *)),
+ SLOT( slotResult( KIO::Job *)));
+ mount_jobs[job] = &data;
+ // The caller expects the device to be unmounted when the function
+ // completes. Thus block until the job completes.
+ while (!data.completed) {
+ kapp->eventLoop()->enterLoop();
+ }
+ // Return the error message (if any) to the caller
+ return (data.error) ? data.errorMessage : QString::null;
+ }
+
+ DBusMessage *dmesg, *reply;
+ DBusError error;
+ const char *options[2];
+
+ const char *udi = medium->id().latin1();
+ kdDebug() << "unmounting " << udi << "..." << endl;
+
+ dbus_error_init(&error);
+ DBusConnection *dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (dbus_error_is_set(&error))
+ {
+ dbus_error_free(&error);
+ return false;
+ }
+
+ if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume",
+ "Unmount"))) {
+ kdDebug() << "unmount failed for " << udi << ": could not create dbus message\n";
+ return i18n("Internal Error");
+ }
+
+ options[0] = "force";
+ options[1] = 0;
+
+ if (!dbus_message_append_args (dmesg, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, 0,
+ DBUS_TYPE_INVALID))
+ {
+ kdDebug() << "unmount failed for " << udi << ": could not append args to dbus message\n";
+ dbus_message_unref (dmesg);
+ return i18n("Internal Error");
+ }
+
+ dbus_error_init (&error);
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error)))
+ {
+ QString qerror, reason;
+
+ kdDebug() << "unmount failed for " << udi << ": " << error.name << " " << error.message << endl;
+ qerror = "<qt>";
+ qerror += "<p>" + i18n("Unfortunately, the device <b>%1</b> (%2) named <b>'%3'</b> and "
+ "currently mounted at <b>%4</b> could not be unmounted. ").arg(
+ "system:/media/" + medium->name(),
+ medium->deviceNode(),
+ medium->prettyLabel(),
+ medium->prettyBaseURL().pathOrURL()) + "</p>";
+ qerror += "<p>" + i18n("Unmounting failed due to the following error:") + "</p>";
+ if (!strcmp(error.name, "org.freedesktop.Hal.Device.Volume.Busy")) {
+ reason = i18n("Device is Busy:");
+ } else if (!strcmp(error.name, "org.freedesktop.Hal.Device.Volume.NotMounted")) {
+ // this is faking. The error is that the device wasn't mounted by hal (but by the system)
+ reason = i18n("Permissions denied");
+ } else {
+ reason = error.message;
+ }
+ qerror += "<p><b>" + reason + "</b></p>";
+
+ // Include list of processes (if any) using the device in the error message
+ reason = listUsingProcesses(medium);
+ if (!reason.isEmpty()) {
+ qerror += reason;
+ }
+
+ dbus_message_unref (dmesg);
+ dbus_error_free (&error);
+ return qerror;
+ }
+
+ kdDebug() << "unmount queued for " << udi << endl;
+
+ dbus_message_unref (dmesg);
+ dbus_message_unref (reply);
+
+ medium->setHalMounted(false);
+ ResetProperties(udi);
+
+ return QString();
+}
+
+#include "halbackend.moc"
diff --git a/kioslave/media/mediamanager/halbackend.h b/kioslave/media/mediamanager/halbackend.h
new file mode 100644
index 000000000..31c682374
--- /dev/null
+++ b/kioslave/media/mediamanager/halbackend.h
@@ -0,0 +1,228 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+* This is a media:/ backend for the freedesktop Hardware Abstraction Layer
+* Usage : create an instance of HALBackend, then call InitHal(). A false
+* result from the later function means that something went wrong and that
+* the backend shall not be used.
+*
+* @author Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org>
+* @short media:/ backend for the HAL
+*/
+
+#ifndef _HALBACKEND_H_
+#define _HALBACKEND_H_
+
+#include "backendbase.h"
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qstring.h>
+
+#include <config.h>
+
+/* We acknowledge the the dbus API is unstable */
+#define DBUS_API_SUBJECT_TO_CHANGE
+/* DBus-Qt bindings */
+#include <dbus/connection.h>
+/* HAL libraries */
+#include <libhal.h>
+#include <libhal-storage.h>
+
+namespace KIO {
+ class Job;
+}
+
+class HALBackend : public QObject, public BackendBase
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ HALBackend(MediaList &list, QObject* parent);
+
+ /**
+ * Destructor
+ */
+ ~HALBackend();
+
+ /**
+ * Perform HAL initialization.
+ *
+ * @return true if succeded. If not, rely on some other backend
+ */
+ bool InitHal();
+
+ /**
+ * List all devices and append them to the media device list (called only once, at startup).
+ *
+ * @return true if succeded, false otherwise
+ */
+ bool ListDevices();
+
+ QStringList mountoptions(const QString &id);
+
+ bool setMountoptions(const QString &id, const QStringList &options);
+
+ QString mount(const QString &id);
+ QString mount(const Medium *medium);
+ QString unmount(const QString &id);
+
+private:
+ /**
+ * Append a device in the media list. This function will check if the device
+ * is worth listing.
+ *
+ * @param udi Universal Device Id
+ * @param allowNotification Indicates if this event will be notified to the user
+ */
+ void AddDevice(const char* udi, bool allowNotification=true);
+
+ /**
+ * Remove a device from the device list
+ *
+ * @param udi Universal Device Id
+ */
+ void RemoveDevice(const char* udi);
+
+ /**
+ * A device has changed, update it
+ *
+ * @param udi Universal Device Id
+ */
+ void ModifyDevice(const char *udi, const char* key);
+
+ /**
+ * HAL informed that a special action has occured
+ * (e.g. device unplugged without unmounting)
+ *
+ * @param udi Universal Device Id
+ */
+ void DeviceCondition(const char *udi, const char *condition);
+
+ /**
+ * Integrate the DBus connection within qt main loop
+ */
+ void MainLoopIntegration(DBusConnection *dbusConnection);
+
+/* Set media properties */
+private:
+ /**
+ * Reset properties for the given medium
+ */
+ void ResetProperties(const char* MediumUdi, bool allowNotification=false);
+
+ /**
+ * Find the medium that is concerned with device udi
+ */
+ const char* findMediumUdiFromUdi(const char* udi);
+
+ void setVolumeProperties(Medium* medium);
+ bool setFloppyProperties(Medium* medium);
+ void setFloppyMountState( Medium* medium );
+ bool setFstabProperties(Medium* medium);
+ void setCameraProperties(Medium* medium);
+ QString generateName(const QString &devNode);
+ static QString isInFstab(const Medium *medium);
+ static QString listUsingProcesses(const Medium *medium);
+
+private slots:
+ void slotResult(KIO::Job *job);
+
+/* Hal call-backs -- from gvm*/
+public:
+ /** Invoked when a device is added to the Global Device List.
+ *
+ * @param ctx LibHal context
+ * @param udi Universal Device Id
+ */
+ static void hal_device_added(LibHalContext *ctx, const char *udi);
+
+ /** Invoked when a device is removed from the Global Device List.
+ *
+ * @param ctx LibHal context
+ * @param udi Universal Device Id
+ */
+ static void hal_device_removed(LibHalContext *ctx, const char *udi);
+
+ /** Invoked when a property of a device in the Global Device List is
+ * changed, and we have we have subscribed to changes for that device.
+ *
+ * @param ctx LibHal context
+ * @param udi Univerisal Device Id
+ * @param key Key of property
+ */
+ static void hal_device_property_modified(LibHalContext *ctx, const char *udi, const char *key,
+ dbus_bool_t is_removed, dbus_bool_t is_added);
+
+ /** Type for callback when a non-continuos condition occurs on a device
+ *
+ * @param udi Univerisal Device Id
+ * @param condition_name Name of the condition
+ * @param message D-BUS message with variable parameters depending on condition
+ */
+ static void hal_device_condition(LibHalContext *ctx, const char *udi,
+ const char *condition_name,
+ const char* message
+ );
+
+/* HAL and DBus structures */
+private:
+ /**
+ * The HAL context connecting the whole application to the HAL
+ */
+ LibHalContext* m_halContext;
+
+ /**
+ * libhal-storage HAL policy, e.g. for icon names
+ */
+ LibHalStoragePolicy* m_halStoragePolicy;
+
+ /**
+ * The DBus-Qt bindings connection for mainloop integration
+ */
+ DBusQt::Connection* m_dBusQtConnection;
+
+ /**
+ * Object for the kded module
+ */
+ QObject* m_parent;
+
+ DBusConnection *dbus_connection;
+
+ /**
+ * Data structure for fstab mount/unmount jobs
+ */
+ struct mount_job_data {
+ // [in] Medium, which is being mounted/unmounted by the job
+ const Medium* medium;
+ // [in,out] Should be set to true when the job completes
+ bool completed;
+ // [out] KIO::Error if an error occured during operation. Otherwise, 0
+ int error;
+ // [out] Error message to be displayed to the user
+ QString errorMessage;
+ };
+
+ QMap<KIO::Job *, struct mount_job_data*> mount_jobs;
+};
+
+#endif /* _HALBACKEND_H_ */
diff --git a/kioslave/media/mediamanager/linuxcdpolling.cpp b/kioslave/media/mediamanager/linuxcdpolling.cpp
new file mode 100644
index 000000000..7519023fe
--- /dev/null
+++ b/kioslave/media/mediamanager/linuxcdpolling.cpp
@@ -0,0 +1,585 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2003 Gav Wood <gav kde org>
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/* Some code of this file comes from kdeautorun */
+
+#include "linuxcdpolling.h"
+
+#include <qthread.h>
+#include <qmutex.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+
+#include "fstabbackend.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// Never ever include directly a kernel header!
+// #include <linux/cdrom.h>
+// Instead we redefine the necessary (copied from the header)
+
+/* This struct is used by the CDROMREADTOCHDR ioctl */
+struct cdrom_tochdr
+{
+ unsigned char cdth_trk0; /* start track */
+ unsigned char cdth_trk1; /* end track */
+};
+
+#define CDROMREADTOCHDR 0x5305 /* Read TOC header
+ (struct cdrom_tochdr) */
+#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
+#define CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */
+
+/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
+#define CDS_NO_INFO 0 /* if not implemented */
+#define CDS_NO_DISC 1
+#define CDS_TRAY_OPEN 2
+#define CDS_DRIVE_NOT_READY 3
+#define CDS_DISC_OK 4
+
+/* return values for the CDROM_DISC_STATUS ioctl */
+/* can also return CDS_NO_[INFO|DISC], from above */
+#define CDS_AUDIO 100
+#define CDS_DATA_1 101
+#define CDS_DATA_2 102
+#define CDS_XA_2_1 103
+#define CDS_XA_2_2 104
+#define CDS_MIXED 105
+
+#define CDSL_CURRENT ((int) (~0U>>1))
+
+// -------
+
+
+
+DiscType::DiscType(Type type)
+ : m_type(type)
+{
+}
+
+bool DiscType::isKnownDisc() const
+{
+ return m_type != None
+ && m_type != Unknown
+ && m_type != UnknownType
+ && m_type != Broken;
+}
+
+bool DiscType::isDisc() const
+{
+ return m_type != None
+ && m_type != Unknown
+ && m_type != Broken;
+}
+
+bool DiscType::isNotDisc() const
+{
+ return m_type == None;
+}
+
+bool DiscType::isData() const
+{
+ return m_type == Data;
+}
+
+DiscType::operator int() const
+{
+ return (int)m_type;
+}
+
+
+class PollingThread : public QThread
+{
+public:
+ PollingThread(const QCString &devNode) : m_dev(devNode)
+ {
+ kdDebug(1219) << "PollingThread::PollingThread("
+ << devNode << ")" << endl;
+ m_stop = false;
+ m_currentType = DiscType::None;
+ m_lastPollType = DiscType::None;
+ }
+
+
+ void stop()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_stop = true;
+ }
+
+ bool hasChanged()
+ {
+ QMutexLocker locker(&m_mutex);
+
+ return m_currentType!=m_lastPollType;
+ }
+
+ DiscType type()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_currentType = m_lastPollType;
+ return m_currentType;
+ }
+
+protected:
+ virtual void run()
+ {
+ kdDebug(1219) << "PollingThread(" << m_dev << ") start" << endl;
+ while (!m_stop && m_lastPollType!=DiscType::Broken)
+ {
+ m_mutex.lock();
+ DiscType type = m_lastPollType;
+ m_mutex.unlock();
+
+ type = LinuxCDPolling::identifyDiscType(m_dev, type);
+
+ m_mutex.lock();
+ m_lastPollType = type;
+ m_mutex.unlock();
+
+ msleep(500);
+ }
+ kdDebug(1219) << "PollingThread(" << m_dev << ") stop" << endl;
+ }
+
+private:
+ QMutex m_mutex;
+ bool m_stop;
+ const QCString m_dev;
+ DiscType m_currentType;
+ DiscType m_lastPollType;
+};
+
+
+LinuxCDPolling::LinuxCDPolling(MediaList &list)
+ : QObject(), BackendBase(list)
+{
+ connect(&m_mediaList, SIGNAL(mediumAdded(const QString &,
+ const QString &, bool)),
+ this, SLOT(slotMediumAdded(const QString &)) );
+
+ connect(&m_mediaList, SIGNAL(mediumRemoved(const QString &,
+ const QString &, bool)),
+ this, SLOT(slotMediumRemoved(const QString &)) );
+
+ connect(&m_mediaList, SIGNAL(mediumStateChanged(const QString &,
+ const QString &, bool, bool)),
+ this, SLOT(slotMediumStateChanged(const QString &)) );
+
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+}
+
+LinuxCDPolling::~LinuxCDPolling()
+{
+ QMap<QString, PollingThread*>::iterator it = m_threads.begin();
+ QMap<QString, PollingThread*>::iterator end = m_threads.end();
+
+ for(; it!=end; ++it)
+ {
+ PollingThread *thread = it.data();
+ thread->stop();
+ thread->wait();
+ delete thread;
+ }
+}
+
+void LinuxCDPolling::slotMediumAdded(const QString &id)
+{
+ kdDebug(1219) << "LinuxCDPolling::slotMediumAdded(" << id << ")" << endl;
+
+ if (m_threads.contains(id)) return;
+
+ const Medium *medium = m_mediaList.findById(id);
+
+ QString mime = medium->mimeType();
+ kdDebug(1219) << "mime == " << mime << endl;
+
+ if (mime.find("dvd")==-1 && mime.find("cd")==-1) return;
+
+ if (!medium->isMounted())
+ {
+ m_excludeNotification.append( id );
+
+ QCString dev = QFile::encodeName( medium->deviceNode() ).data();
+ PollingThread *thread = new PollingThread(dev);
+ m_threads[id] = thread;
+ thread->start();
+ m_timer.start(500);
+ }
+}
+
+void LinuxCDPolling::slotMediumRemoved(const QString &id)
+{
+ kdDebug(1219) << "LinuxCDPolling::slotMediumRemoved(" << id << ")" << endl;
+
+ if (!m_threads.contains(id)) return;
+
+ PollingThread *thread = m_threads[id];
+ m_threads.remove(id);
+ thread->stop();
+ thread->wait();
+ delete thread;
+
+ m_excludeNotification.remove(id);
+}
+
+void LinuxCDPolling::slotMediumStateChanged(const QString &id)
+{
+ kdDebug(1219) << "LinuxCDPolling::slotMediumStateChanged("
+ << id << ")" << endl;
+
+ const Medium *medium = m_mediaList.findById(id);
+
+ QString mime = medium->mimeType();
+ kdDebug(1219) << "mime == " << mime << endl;
+
+ if (mime.find("dvd")==-1 && mime.find("cd")==-1) return;
+
+ if (!m_threads.contains(id) && !medium->isMounted())
+ {
+ // It is just a mount state change, no need to notify
+ m_excludeNotification.append( id );
+
+ QCString dev = QFile::encodeName( medium->deviceNode() ).data();
+ PollingThread *thread = new PollingThread(dev);
+ m_threads[id] = thread;
+ thread->start();
+ m_timer.start(500);
+ }
+ else if (m_threads.contains(id) && medium->isMounted())
+ {
+ PollingThread *thread = m_threads[id];
+ m_threads.remove(id);
+ thread->stop();
+ thread->wait();
+ delete thread;
+ }
+}
+
+void LinuxCDPolling::slotTimeout()
+{
+ //kdDebug(1219) << "LinuxCDPolling::slotTimeout()" << endl;
+
+ if (m_threads.isEmpty())
+ {
+ m_timer.stop();
+ return;
+ }
+
+ QMap<QString, PollingThread*>::iterator it = m_threads.begin();
+ QMap<QString, PollingThread*>::iterator end = m_threads.end();
+
+ for(; it!=end; ++it)
+ {
+ QString id = it.key();
+ PollingThread *thread = it.data();
+
+ if (thread->hasChanged())
+ {
+ DiscType type = thread->type();
+ const Medium *medium = m_mediaList.findById(id);
+ applyType(type, medium);
+ }
+ }
+}
+
+static QString baseType(const Medium *medium)
+{
+ kdDebug(1219) << "baseType(" << medium->id() << ")" << endl;
+
+ QString devNode = medium->deviceNode();
+ QString mountPoint = medium->mountPoint();
+ QString fsType = medium->fsType();
+ bool mounted = medium->isMounted();
+
+ QString mimeType, iconName, label;
+
+ FstabBackend::guess(devNode, mountPoint, fsType, mounted,
+ mimeType, iconName, label);
+
+ if (devNode.find("dvd")!=-1)
+ {
+ kdDebug(1219) << "=> dvd" << endl;
+ return "dvd";
+ }
+ else
+ {
+ kdDebug(1219) << "=> cd" << endl;
+ return "cd";
+ }
+}
+
+static void restoreEmptyState(MediaList &list, const Medium *medium,
+ bool allowNotification)
+{
+ kdDebug(1219) << "restoreEmptyState(" << medium->id() << ")" << endl;
+
+ QString id = medium->id();
+ QString devNode = medium->deviceNode();
+ QString mountPoint = medium->mountPoint();
+ QString fsType = medium->fsType();
+ bool mounted = medium->isMounted();
+
+ QString mimeType, iconName, label;
+
+ FstabBackend::guess(devNode, mountPoint, fsType, mounted,
+ mimeType, iconName, label);
+
+ list.changeMediumState(id, devNode, mountPoint, fsType, mounted,
+ allowNotification, mimeType, iconName, label);
+}
+
+
+void LinuxCDPolling::applyType(DiscType type, const Medium *medium)
+{
+ kdDebug(1219) << "LinuxCDPolling::applyType(" << type << ", "
+ << medium->id() << ")" << endl;
+
+ QString id = medium->id();
+ QString dev = medium->deviceNode();
+
+ bool notify = !m_excludeNotification.contains(id);
+ m_excludeNotification.remove(id);
+
+ switch (type)
+ {
+ case DiscType::Data:
+ restoreEmptyState(m_mediaList, medium, notify);
+ break;
+ case DiscType::Audio:
+ case DiscType::Mixed:
+ m_mediaList.changeMediumState(id, "audiocd:/?device="+dev,
+ notify, "media/audiocd");
+ break;
+ case DiscType::VCD:
+ m_mediaList.changeMediumState(id, false, notify, "media/vcd");
+ break;
+ case DiscType::SVCD:
+ m_mediaList.changeMediumState(id, false, notify, "media/svcd");
+ break;
+ case DiscType::DVD:
+ m_mediaList.changeMediumState(id, false, notify, "media/dvdvideo");
+ break;
+ case DiscType::Blank:
+ if (baseType(medium)=="dvd")
+ {
+ m_mediaList.changeMediumState(id, false,
+ notify, "media/blankdvd");
+ }
+ else
+ {
+ m_mediaList.changeMediumState(id, false,
+ notify, "media/blankcd");
+ }
+ break;
+ case DiscType::None:
+ case DiscType::Unknown:
+ case DiscType::UnknownType:
+ restoreEmptyState(m_mediaList, medium, false);
+ break;
+ }
+}
+
+DiscType LinuxCDPolling::identifyDiscType(const QCString &devNode,
+ const DiscType &current)
+{
+ //kdDebug(1219) << "LinuxCDPolling::identifyDiscType("
+ // << devNode << ")" << endl;
+
+ int fd;
+ struct cdrom_tochdr th;
+
+ // open the device
+ fd = open(devNode, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) return DiscType::Broken;
+
+ switch (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT))
+ {
+ case CDS_DISC_OK:
+ {
+ if (current.isDisc())
+ {
+ close(fd);
+ return current;
+ }
+
+ // see if we can read the disc's table of contents (TOC).
+ if (ioctl(fd, CDROMREADTOCHDR, &th))
+ {
+ close(fd);
+ return DiscType::Blank;
+ }
+
+ // read disc status info
+ int status = ioctl(fd, CDROM_DISC_STATUS, CDSL_CURRENT);
+
+ // release the device
+ close(fd);
+
+ switch (status)
+ {
+ case CDS_AUDIO:
+ return DiscType::Audio;
+ case CDS_DATA_1:
+ case CDS_DATA_2:
+ if (hasDirectory(devNode, "video_ts"))
+ {
+ return DiscType::DVD;
+ }
+ else if (hasDirectory(devNode, "vcd"))
+ {
+ return DiscType::VCD;
+ }
+ else if (hasDirectory(devNode, "svcd"))
+ {
+ return DiscType::SVCD;
+ }
+ else
+ {
+ return DiscType::Data;
+ }
+ case CDS_MIXED:
+ return DiscType::Mixed;
+ default:
+ return DiscType::UnknownType;
+ }
+ }
+ case CDS_NO_INFO:
+ close(fd);
+ return DiscType::Unknown;
+ default:
+ close(fd);
+ return DiscType::None;
+ }
+}
+
+bool LinuxCDPolling::hasDirectory(const QCString &devNode, const QCString &dir)
+{
+ bool ret = false; // return value
+ int fd = 0; // file descriptor for drive
+ unsigned short bs; // the discs block size
+ unsigned short ts; // the path table size
+ unsigned int tl; // the path table location (in blocks)
+ unsigned char len_di = 0; // length of the directory name in current path table entry
+ unsigned int parent = 0; // the number of the parent directory's path table entry
+ char dirname[256]; // filename for the current path table entry
+ int pos = 0; // our position into the path table
+ int curr_record = 1; // the path table record we're on
+ QCString fixed_directory = dir.upper(); // the uppercase version of the "directory" parameter
+
+ // open the drive
+ fd = open(devNode, O_RDONLY | O_NONBLOCK);
+ if (fd == -1) return false;
+
+ // read the block size
+ lseek(fd, 0x8080, SEEK_CUR);
+ if (read(fd, &bs, 2) != 2)
+ {
+ close(fd);
+ return false;
+ }
+ if (Q_BYTE_ORDER != Q_LITTLE_ENDIAN)
+ bs = ((bs << 8) & 0xFF00) | ((bs >> 8) & 0xFF);
+
+ // read in size of path table
+ lseek(fd, 2, SEEK_CUR);
+ if (read(fd, &ts, 2) != 2)
+ {
+ close(fd);
+ return false;
+ }
+ if (Q_BYTE_ORDER != Q_LITTLE_ENDIAN)
+ ts = ((ts << 8) & 0xFF00) | ((ts >> 8) & 0xFF);
+
+ // read in which block path table is in
+ lseek(fd, 6, SEEK_CUR);
+ if (read(fd, &tl, 4) != 4)
+ {
+ close(fd);
+ return false;
+ }
+ if (Q_BYTE_ORDER != Q_LITTLE_ENDIAN)
+ tl = ((tl << 24) & 0xFF000000) | ((tl << 8) & 0xFF0000) |
+ ((tl >> 8) & 0xFF00) | ((tl >> 24) & 0xFF);
+
+ // seek to the path table
+ lseek(fd, bs * tl, SEEK_SET);
+
+ // loop through the path table entries
+ while (pos < ts)
+ {
+ // get the length of the filename of the current entry
+ if (read(fd, &len_di, 1) != 1)
+ {
+ ret = false;
+ break;
+ }
+
+ // get the record number of this entry's parent
+ // i'm pretty sure that the 1st entry is always the top directory
+ lseek(fd, 5, SEEK_CUR);
+ if (read(fd, &parent, 2) != 2)
+ {
+ ret = false;
+ break;
+ }
+ if (Q_BYTE_ORDER != Q_LITTLE_ENDIAN)
+ parent = ((parent << 8) & 0xFF00) | ((parent >> 8) & 0xFF);
+
+ // read the name
+ if (read(fd, dirname, len_di) != len_di)
+ {
+ ret = false;
+ break;
+ }
+ dirname[len_di] = 0;
+ qstrcpy(dirname, QCString(dirname).upper());
+
+ // if we found a folder that has the root as a parent, and the directory name matches
+ // then return success
+ if ((parent == 1) && (dirname == fixed_directory))
+ {
+ ret = true;
+ break;
+ }
+
+ // all path table entries are padded to be even, so if this is an odd-length table, seek a byte to fix it
+ if (len_di%2 == 1)
+ {
+ lseek(fd, 1, SEEK_CUR);
+ pos++;
+ }
+
+ // update our position
+ pos += 8 + len_di;
+ curr_record++;
+ }
+
+ close(fd);
+ return ret;
+}
+
+
+#include "linuxcdpolling.moc"
diff --git a/kioslave/media/mediamanager/linuxcdpolling.h b/kioslave/media/mediamanager/linuxcdpolling.h
new file mode 100644
index 000000000..1df113962
--- /dev/null
+++ b/kioslave/media/mediamanager/linuxcdpolling.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _LINUXCDPOLLING_H_
+#define _LINUXCDPOLLING_H_
+
+#include "backendbase.h"
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <qtimer.h>
+
+class DiscType
+{
+public:
+ enum Type { None, Unknown, Audio, Data, DVD, Mixed,
+ Blank, VCD, SVCD, UnknownType, Broken };
+
+ DiscType(Type type = Unknown);
+
+ bool isKnownDisc() const;
+ bool isDisc() const;
+ bool isNotDisc() const;
+ bool isData() const;
+
+ operator int() const;
+
+private:
+ Type m_type;
+};
+
+class PollingThread;
+
+class LinuxCDPolling : public QObject, public BackendBase
+{
+Q_OBJECT
+
+public:
+
+ LinuxCDPolling(MediaList &list);
+ virtual ~LinuxCDPolling();
+
+ /**
+ * Find the disc type of the medium inserted in a drive
+ * (considered to be a cdrom or dvdrom)
+ *
+ * @param devNode the path to the device to test
+ * @param current the current known state of the drive
+ * @return the disc type
+ */
+ static DiscType identifyDiscType(const QCString &devNode,
+ const DiscType &current = DiscType::Unknown);
+
+private slots:
+ void slotMediumAdded(const QString &id);
+ void slotMediumRemoved(const QString &id);
+ void slotMediumStateChanged(const QString &id);
+ void slotTimeout();
+
+private:
+ void applyType(DiscType type, const Medium *medium);
+
+ static bool hasDirectory(const QCString &devNode, const QCString &dir);
+
+ QMap<QString, PollingThread*> m_threads;
+ QStringList m_excludeNotification;
+ QTimer m_timer;
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/mediadirnotify.cpp b/kioslave/media/mediamanager/mediadirnotify.cpp
new file mode 100644
index 000000000..340414634
--- /dev/null
+++ b/kioslave/media/mediamanager/mediadirnotify.cpp
@@ -0,0 +1,124 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mediadirnotify.h"
+
+#include <kdebug.h>
+
+#include <kdirnotify_stub.h>
+
+#include "medium.h"
+
+MediaDirNotify::MediaDirNotify(const MediaList &list)
+ : m_mediaList(list)
+{
+
+}
+
+KURL::List MediaDirNotify::toMediaURL(const KURL &url)
+{
+ kdDebug(1219) << "MediaDirNotify::toMediaURL(" << url << ")" << endl;
+
+ KURL::List result;
+
+ const QPtrList<Medium> list = m_mediaList.list();
+
+ QPtrList<Medium>::const_iterator it = list.begin();
+ QPtrList<Medium>::const_iterator end = list.end();
+
+ for (; it!=end; ++it)
+ {
+ const Medium *m = *it;
+ KURL base = m->prettyBaseURL();
+
+ if ( base.isParentOf(url) )
+ {
+ QString path = KURL::relativePath(base.path(),
+ url.path());
+
+ KURL new_url("media:/"+m->name()+"/"+path );
+ new_url.cleanPath();
+
+ result.append(new_url);
+ }
+ }
+
+ kdDebug(1219) << result << endl;
+ return result;
+}
+
+KURL::List MediaDirNotify::toMediaURLList(const KURL::List &list)
+{
+ KURL::List new_list;
+
+ KURL::List::const_iterator it = list.begin();
+ KURL::List::const_iterator end = list.end();
+
+ for (; it!=end; ++it)
+ {
+ KURL::List urls = toMediaURL(*it);
+
+ if (!urls.isEmpty())
+ {
+ new_list += urls;
+ }
+ }
+
+ return new_list;
+}
+
+ASYNC MediaDirNotify::FilesAdded(const KURL &directory)
+{
+ KURL::List new_urls = toMediaURL(directory);
+
+ if (!new_urls.isEmpty())
+ {
+ KDirNotify_stub notifier("*", "*");
+
+ KURL::List::const_iterator it = new_urls.begin();
+ KURL::List::const_iterator end = new_urls.end();
+
+ for (; it!=end; ++it)
+ {
+ notifier.FilesAdded(*it);
+ }
+ }
+}
+
+ASYNC MediaDirNotify::FilesRemoved(const KURL::List &fileList)
+{
+ KURL::List new_list = toMediaURLList(fileList);
+
+ if (!new_list.isEmpty())
+ {
+ KDirNotify_stub notifier("*", "*");
+ notifier.FilesRemoved( new_list );
+ }
+}
+
+ASYNC MediaDirNotify::FilesChanged(const KURL::List &fileList)
+{
+ KURL::List new_list = toMediaURLList(fileList);
+
+ if (!new_list.isEmpty())
+ {
+ KDirNotify_stub notifier("*", "*");
+ notifier.FilesChanged( new_list );
+ }
+}
+
diff --git a/kioslave/media/mediamanager/mediadirnotify.h b/kioslave/media/mediamanager/mediadirnotify.h
new file mode 100644
index 000000000..beb1b8849
--- /dev/null
+++ b/kioslave/media/mediamanager/mediadirnotify.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _MEDIADIRNOTIFY_H_
+#define _MEDIADIRNOTIFY_H_
+
+#include <kurl.h>
+#include <kdirnotify.h>
+
+#include "medialist.h"
+
+
+class MediaDirNotify : public KDirNotify
+{
+K_DCOP
+
+public:
+ MediaDirNotify(const MediaList &list);
+
+k_dcop:
+ virtual ASYNC FilesAdded (const KURL &directory);
+ virtual ASYNC FilesRemoved (const KURL::List &fileList);
+ virtual ASYNC FilesChanged (const KURL::List &fileList);
+
+private:
+ KURL::List toMediaURL(const KURL &url);
+ KURL::List toMediaURLList(const KURL::List &list);
+
+ const MediaList &m_mediaList;
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/medialist.cpp b/kioslave/media/mediamanager/medialist.cpp
new file mode 100644
index 000000000..fed6091fb
--- /dev/null
+++ b/kioslave/media/mediamanager/medialist.cpp
@@ -0,0 +1,288 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "medialist.h"
+
+#include <kdebug.h>
+
+MediaList::MediaList()
+{
+ kdDebug(1219) << "MediaList::MediaList()" << endl;
+
+ m_media.setAutoDelete(true);
+}
+
+const QPtrList<Medium> MediaList::list() const
+{
+ kdDebug(1219) << "MediaList::list()" << endl;
+
+ return m_media;
+}
+
+const Medium *MediaList::findById(const QString &id) const
+{
+ kdDebug(1219) << "MediaList::findById(" << id << ")" << endl;
+
+ if ( !m_idMap.contains(id) ) return 0L;
+
+ return m_idMap[id];
+}
+
+const Medium *MediaList::findByName(const QString &name) const
+{
+ kdDebug(1219) << "MediaList::findByName(" << name << ")" << endl;
+
+ if ( !m_nameMap.contains(name) ) return 0L;
+
+ return m_nameMap[name];
+}
+
+
+QString MediaList::addMedium(Medium *medium, bool allowNotification)
+{
+ kdDebug(1219) << "MediaList::addMedium(@" << medium->id() << ")" << endl;
+
+ QString id = medium->id();
+ if ( m_idMap.contains(id) ) return QString::null;
+
+ m_media.append( medium );
+ m_idMap[id] = medium;
+
+ QString name = medium->name();
+ if ( !m_nameMap.contains(name) )
+ {
+ m_nameMap[name] = medium;
+
+ kdDebug(1219) << "MediaList emits mediumAdded(" << id << ", "
+ << name << ")" << endl;
+ emit mediumAdded(id, name, allowNotification);
+
+ return name;
+ }
+
+ QString base_name = name+"_";
+ int i = 1;
+
+ while ( m_nameMap.contains(base_name+QString::number(i)) )
+ {
+ i++;
+ }
+
+ name = base_name+QString::number(i);
+ medium->setName(name);
+ m_nameMap[name] = medium;
+
+ kdDebug(1219) << "MediaList emits mediumAdded(" << id << ", "
+ << name << ")" << endl;
+ emit mediumAdded(id, name, allowNotification);
+ return name;
+}
+
+bool MediaList::removeMedium(const QString &id, bool allowNotification)
+{
+ kdDebug(1219) << "MediaList::removeMedium(" << id << ")" << endl;
+
+ if ( !m_idMap.contains(id) ) return false;
+
+ Medium *medium = m_idMap[id];
+ QString name = medium->name();
+
+ m_idMap.remove(id);
+ m_nameMap.remove( medium->name() );
+ m_media.remove( medium );
+
+ emit mediumRemoved(id, name, allowNotification);
+ return true;
+}
+
+bool MediaList::changeMediumState(const Medium &medium, bool allowNotification)
+{
+ kdDebug(1219) << "MediaList::changeMediumState(const Medium &)" << endl;
+
+ if ( !m_idMap.contains(medium.id()) ) return false;
+
+ Medium *m = m_idMap[medium.id()];
+
+ if ( medium.isMountable() )
+ {
+ QString device_node = medium.deviceNode();
+ QString mount_point = medium.mountPoint();
+ QString fs_type = medium.fsType();
+ bool mounted = medium.isMounted();
+
+ m->mountableState( device_node, mount_point,
+ fs_type, mounted );
+ }
+ else
+ {
+ m->unmountableState( medium.baseURL() );
+ }
+
+
+ if (!medium.mimeType().isEmpty())
+ {
+ m->setMimeType( medium.mimeType() );
+ }
+
+ if (!medium.iconName().isEmpty())
+ {
+ m->setIconName( medium.iconName() );
+ }
+
+ if (!medium.label().isEmpty())
+ {
+ m->setLabel( medium.label() );
+ }
+
+ emit mediumStateChanged(m->id(), m->name(), !m->needMounting(), allowNotification);
+ return true;
+}
+
+bool MediaList::changeMediumState(const QString &id,
+ const QString &baseURL,
+ bool allowNotification,
+ const QString &mimeType,
+ const QString &iconName,
+ const QString &label)
+{
+ kdDebug(1219) << "MediaList::changeMediumState(" << id << ", "
+ << baseURL << ", " << mimeType << ", " << iconName << ")"
+ << endl;
+
+ if ( !m_idMap.contains(id) ) return false;
+
+ Medium *medium = m_idMap[id];
+
+ medium->unmountableState( baseURL );
+
+ if (!mimeType.isEmpty())
+ {
+ medium->setMimeType( mimeType );
+ }
+
+ if (!iconName.isEmpty())
+ {
+ medium->setIconName( iconName );
+ }
+
+ if (!label.isEmpty())
+ {
+ medium->setLabel( label );
+ }
+
+ emit mediumStateChanged(id, medium->name(),
+ !medium->needMounting(),
+ allowNotification);
+ return true;
+}
+
+bool MediaList::changeMediumState(const QString &id,
+ const QString &deviceNode,
+ const QString &mountPoint,
+ const QString &fsType, bool mounted,
+ bool allowNotification,
+ const QString &mimeType,
+ const QString &iconName,
+ const QString &label)
+{
+ kdDebug(1219) << "MediaList::changeMediumState(" << id << ", "
+ << deviceNode << ", " << mountPoint << ", " << fsType << ", "
+ << mounted << ", " << mimeType << ", " << iconName << ")"
+ << endl;
+
+ if ( !m_idMap.contains(id) ) return false;
+
+ Medium *medium = m_idMap[id];
+
+ medium->mountableState( deviceNode, mountPoint, fsType, mounted );
+
+ if (!mimeType.isEmpty())
+ {
+ medium->setMimeType( mimeType );
+ }
+
+ if (!iconName.isEmpty())
+ {
+ medium->setIconName( iconName );
+ }
+
+ if (!label.isEmpty())
+ {
+ medium->setLabel( label );
+ }
+
+ emit mediumStateChanged(id, medium->name(),
+ !medium->needMounting(),
+ allowNotification);
+ return true;
+}
+
+bool MediaList::changeMediumState(const QString &id, bool mounted,
+ bool allowNotification,
+ const QString &mimeType,
+ const QString &iconName,
+ const QString &label)
+{
+ kdDebug(1219) << "MediaList::changeMediumState(" << id << ", "
+ << mounted << ", " << mimeType << ", " << iconName << ")"
+ << endl;
+
+ if ( !m_idMap.contains(id) ) return false;
+
+ Medium *medium = m_idMap[id];
+
+ if ( !medium->mountableState( mounted ) ) return false;
+
+ if (!mimeType.isEmpty())
+ {
+ medium->setMimeType( mimeType );
+ }
+
+ if (!iconName.isEmpty())
+ {
+ medium->setIconName( iconName );
+ }
+
+ if (!label.isEmpty())
+ {
+ medium->setLabel( label );
+ }
+
+ emit mediumStateChanged(id, medium->name(),
+ !medium->needMounting(),
+ allowNotification);
+ return true;
+}
+
+bool MediaList::setUserLabel(const QString &name, const QString &label)
+{
+ kdDebug(1219) << "MediaList::setUserLabel(" << name << ", "
+ << label << ")" << endl;
+
+ if ( !m_nameMap.contains(name) ) return false;
+
+ Medium *medium = m_nameMap[name];
+ medium->setUserLabel(label);
+
+ emit mediumStateChanged(medium->id(), name,
+ !medium->needMounting(),
+ false);
+ return true;
+}
+
+#include "medialist.moc"
diff --git a/kioslave/media/mediamanager/medialist.h b/kioslave/media/mediamanager/medialist.h
new file mode 100644
index 000000000..590491b0c
--- /dev/null
+++ b/kioslave/media/mediamanager/medialist.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _MEDIALIST_H_
+#define _MEDIALIST_H_
+
+#include <qobject.h>
+
+#include "medium.h"
+
+class MediaList : public QObject
+{
+Q_OBJECT
+
+public:
+ MediaList();
+
+ // FIXME: should be <const Medium> or something similar...
+ const QPtrList<Medium> list() const;
+ const Medium *findById(const QString &id) const;
+ const Medium *findByName(const QString &name) const;
+
+public:
+ QString addMedium(Medium *medium, bool allowNotification = true);
+ bool removeMedium(const QString &id, bool allowNotification = true);
+
+ bool changeMediumState(const Medium &medium, bool allowNotification);
+ bool changeMediumState(const QString &id,
+ const QString &baseURL,
+ bool allowNotification = true,
+ const QString &mimeType = QString::null,
+ const QString &iconName = QString::null,
+ const QString &label = QString::null);
+ bool changeMediumState(const QString &id,
+ const QString &deviceNode,
+ const QString &mountPoint,
+ const QString &fsType, bool mounted,
+ bool allowNotification = true,
+ const QString &mimeType = QString::null,
+ const QString &iconName = QString::null,
+ const QString &label = QString::null);
+ bool changeMediumState(const QString &id, bool mounted,
+ bool allowNotification = true,
+ const QString &mimeType = QString::null,
+ const QString &iconName = QString::null,
+ const QString &label = QString::null);
+
+ bool setUserLabel(const QString &name, const QString &label);
+
+signals:
+ void mediumAdded(const QString &id, const QString &name,
+ bool allowNotification);
+ void mediumRemoved(const QString &id, const QString &name,
+ bool allowNotification);
+ void mediumStateChanged(const QString &id, const QString &name,
+ bool mounted, bool allowNotification);
+
+private:
+ QPtrList<Medium> m_media;
+ QMap<QString,Medium*> m_nameMap;
+ QMap<QString,Medium*> m_idMap;
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/mediamanager.cpp b/kioslave/media/mediamanager/mediamanager.cpp
new file mode 100644
index 000000000..ad8f1b447
--- /dev/null
+++ b/kioslave/media/mediamanager/mediamanager.cpp
@@ -0,0 +1,342 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mediamanager.h"
+
+#include <config.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include <kdirnotify_stub.h>
+#include <kstandarddirs.h>
+
+#include "mediamanagersettings.h"
+
+#include "fstabbackend.h"
+
+#ifdef COMPILE_HALBACKEND
+#include "halbackend.h"
+#endif //COMPILE_HALBACKEND
+
+#ifdef COMPILE_LINUXCDPOLLING
+#include "linuxcdpolling.h"
+#endif //COMPILE_LINUXCDPOLLING
+
+
+MediaManager::MediaManager(const QCString &obj)
+ : KDEDModule(obj), m_dirNotify(m_mediaList)
+{
+ connect( &m_mediaList, SIGNAL(mediumAdded(const QString&, const QString&, bool)),
+ SLOT(slotMediumAdded(const QString&, const QString&, bool)) );
+ connect( &m_mediaList, SIGNAL(mediumRemoved(const QString&, const QString&, bool)),
+ SLOT(slotMediumRemoved(const QString&, const QString&, bool)) );
+ connect( &m_mediaList,
+ SIGNAL(mediumStateChanged(const QString&, const QString&, bool, bool)),
+ SLOT(slotMediumChanged(const QString&, const QString&, bool, bool)) );
+
+ QTimer::singleShot( 10, this, SLOT( loadBackends() ) );
+}
+
+MediaManager::~MediaManager()
+{
+ while ( !m_backends.isEmpty() )
+ {
+ BackendBase *b = m_backends.first();
+ m_backends.remove( b );
+ delete b;
+ }
+}
+
+void MediaManager::loadBackends()
+{
+ m_mediaList.blockSignals(true);
+
+ while ( !m_backends.isEmpty() )
+ {
+ BackendBase *b = m_backends.first();
+ m_backends.remove( b );
+ delete b;
+ }
+
+ mp_removableBackend = 0L;
+ m_halbackend = 0L;
+ m_fstabbackend = 0L;
+
+#ifdef COMPILE_HALBACKEND
+ if ( MediaManagerSettings::self()->halBackendEnabled() )
+ {
+ m_halbackend = new HALBackend(m_mediaList, this);
+ if (m_halbackend->InitHal())
+ {
+ m_backends.append( m_halbackend );
+ m_fstabbackend = new FstabBackend(m_mediaList, true);
+ m_backends.append( m_fstabbackend );
+ // No need to load something else...
+ m_mediaList.blockSignals(false);
+ return;
+ }
+ else
+ {
+ delete m_halbackend;
+ m_halbackend = 0;
+ }
+ }
+#endif // COMPILE_HALBACKEND
+
+ mp_removableBackend = new RemovableBackend(m_mediaList);
+ m_backends.append( mp_removableBackend );
+
+#ifdef COMPILE_LINUXCDPOLLING
+ if ( MediaManagerSettings::self()->cdPollingEnabled() )
+ {
+ m_backends.append( new LinuxCDPolling(m_mediaList) );
+ }
+#endif //COMPILE_LINUXCDPOLLING
+
+ m_fstabbackend = new FstabBackend(m_mediaList);
+ m_backends.append( m_fstabbackend );
+ m_mediaList.blockSignals(false);
+}
+
+
+QStringList MediaManager::fullList()
+{
+ QPtrList<Medium> list = m_mediaList.list();
+
+ QStringList result;
+
+ QPtrList<Medium>::const_iterator it = list.begin();
+ QPtrList<Medium>::const_iterator end = list.end();
+ for (; it!=end; ++it)
+ {
+ result+= (*it)->properties();
+ result+= Medium::SEPARATOR;
+ }
+
+ return result;
+}
+
+QStringList MediaManager::properties(const QString &name)
+{
+ const Medium *m = m_mediaList.findByName(name);
+
+ if (!m)
+ {
+ KURL u(name);
+ kdDebug() << "Media::prop " << name << " " << u.isValid() << endl;
+ if (u.isValid())
+ {
+ if (u.protocol() == "system")
+ {
+ QString path = u.path();
+ if (path.startsWith("/media/"))
+ path = path.mid(strlen("/media/"));
+ m = m_mediaList.findByName(path);
+ kdDebug() << "findByName " << path << m << endl;
+ }
+ else if (u.protocol() == "media")
+ {
+ m = m_mediaList.findByName(u.filename());
+ kdDebug() << "findByName " << u.filename() << m << endl;
+ }
+ else if (u.protocol() == "file")
+ {
+ // look for the mount point
+ QPtrList<Medium> list = m_mediaList.list();
+ QPtrList<Medium>::const_iterator it = list.begin();
+ QPtrList<Medium>::const_iterator end = list.end();
+ QString path;
+
+ for (; it!=end; ++it)
+ {
+ path = KStandardDirs::realFilePath(u.path());
+ kdDebug() << "comparing " << (*it)->mountPoint() << " " << path << " " << (*it)->deviceNode() << endl;
+ if ((*it)->mountPoint() == path || (*it)->deviceNode() == path) {
+ m = *it;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (m)
+ return m->properties();
+ else
+ return QStringList();
+}
+
+QStringList MediaManager::mountoptions(const QString &name)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return QStringList();
+ return m_halbackend->mountoptions(name);
+#else
+ return QStringList();
+#endif
+}
+
+bool MediaManager::setMountoptions(const QString &name, const QStringList &options)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return false;
+ return m_halbackend->setMountoptions(name, options);
+#else
+ return false;
+#endif
+}
+
+QString MediaManager::mount(const QString &name)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return i18n("Feature only available with HAL");
+ return m_halbackend->mount(name);
+#else
+ if ( !m_fstabbackend ) // lying :)
+ return i18n("Feature only available with HAL");
+ return m_fstabbackend->mount( name );
+#endif
+}
+
+QString MediaManager::unmount(const QString &name)
+{
+#ifdef COMPILE_HALBACKEND
+ if (!m_halbackend)
+ return i18n("Feature only available with HAL");
+ return m_halbackend->unmount(name);
+#else
+ if ( !m_fstabbackend ) // lying :)
+ return i18n("Feature only available with HAL");
+ return m_fstabbackend->unmount( name );
+#endif
+}
+
+QString MediaManager::nameForLabel(const QString &label)
+{
+ const QPtrList<Medium> media = m_mediaList.list();
+
+ QPtrList<Medium>::const_iterator it = media.begin();
+ QPtrList<Medium>::const_iterator end = media.end();
+ for (; it!=end; ++it)
+ {
+ const Medium *m = *it;
+
+ if (m->prettyLabel()==label)
+ {
+ return m->name();
+ }
+ }
+
+ return QString::null;
+}
+
+ASYNC MediaManager::setUserLabel(const QString &name, const QString &label)
+{
+ m_mediaList.setUserLabel(name, label);
+}
+
+ASYNC MediaManager::reloadBackends()
+{
+ MediaManagerSettings::self()->readConfig();
+ loadBackends();
+}
+
+bool MediaManager::removablePlug(const QString &devNode, const QString &label)
+{
+ if (mp_removableBackend)
+ {
+ return mp_removableBackend->plug(devNode, label);
+ }
+ return false;
+}
+
+bool MediaManager::removableUnplug(const QString &devNode)
+{
+ if (mp_removableBackend)
+ {
+ return mp_removableBackend->unplug(devNode);
+ }
+ return false;
+}
+
+bool MediaManager::removableCamera(const QString &devNode)
+{
+ if (mp_removableBackend)
+ {
+ return mp_removableBackend->camera(devNode);
+ }
+ return false;
+}
+
+
+void MediaManager::slotMediumAdded(const QString &/*id*/, const QString &name,
+ bool allowNotification)
+{
+ kdDebug(1219) << "MediaManager::slotMediumAdded: " << name << endl;
+
+ KDirNotify_stub notifier("*", "*");
+ notifier.FilesAdded( KURL("media:/") );
+
+ emit mediumAdded(name, allowNotification);
+ emit mediumAdded(name);
+}
+
+void MediaManager::slotMediumRemoved(const QString &/*id*/, const QString &name,
+ bool allowNotification)
+{
+ kdDebug(1219) << "MediaManager::slotMediumRemoved: " << name << endl;
+
+ KDirNotify_stub notifier("*", "*");
+ notifier.FilesRemoved( KURL("media:/"+name) );
+
+ emit mediumRemoved(name, allowNotification);
+ emit mediumRemoved(name);
+}
+
+void MediaManager::slotMediumChanged(const QString &/*id*/, const QString &name,
+ bool mounted, bool allowNotification)
+{
+ kdDebug(1219) << "MediaManager::slotMediumChanged: " << name << endl;
+
+ KDirNotify_stub notifier("*", "*");
+ if (!mounted)
+ {
+ notifier.FilesRemoved( KURL("media:/"+name) );
+ }
+ notifier.FilesChanged( KURL("media:/"+name) );
+
+ emit mediumChanged(name, allowNotification);
+ emit mediumChanged(name);
+}
+
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_mediamanager(const QCString &obj)
+ {
+ KGlobal::locale()->insertCatalogue("kio_media");
+ return new MediaManager(obj);
+ }
+}
+
+#include "mediamanager.moc"
diff --git a/kioslave/media/mediamanager/mediamanager.desktop b/kioslave/media/mediamanager/mediamanager.desktop
new file mode 100644
index 000000000..88d8e507f
--- /dev/null
+++ b/kioslave/media/mediamanager/mediamanager.desktop
@@ -0,0 +1,141 @@
+[Desktop Entry]
+Type=Service
+Name=KDED Media Manager
+Name[af]=KDED Media Bestuurder
+Name[ar]=مسيير الوسائط KDED
+Name[az]=KDED Mediya İdarəcisi
+Name[be]=Кіраўнік носьбітаў KDED
+Name[bg]=Управление на устройствата KDED
+Name[bn]=কে.ডি.ই.ডি. মিডিয়া ম্যানেজার
+Name[bs]=KDED upravitelj medijima
+Name[ca]=Gestor de suports KDED
+Name[cs]=KDED správce médií
+Name[csb]=Menedżer zôpisownëch mediów dlô KDED
+Name[da]=KDED Mediehåndtering
+Name[de]=Medienverwaltung
+Name[el]=Διαχειριστής μέσων KDED
+Name[eo]=KDatumportila administrilo
+Name[es]=Gestor de dispositivos KDED
+Name[et]=KDED andmekandjate haldur
+Name[eu]=KDED media kudeatzailea
+Name[fa]=مدیر رسانه KDED
+Name[fi]=KDED-tallennusmedianhallinta
+Name[fr]=Gestionnaire de média KDED
+Name[fy]=KDEDED-mediabehearder
+Name[ga]=Bainisteoir Meán KDED
+Name[gl]=Xestor de Meios de KDED
+Name[he]=מנהל המדיה של KDED
+Name[hi]=केडीईडी मीडिया प्रबंधक
+Name[hr]=KDED upravitelj medija
+Name[hu]=KDED médiakezelő
+Name[is]=KDED miðilstjóri
+Name[it]=Gestore dei supporti KDED
+Name[ja]=KDED メディアマネージャ
+Name[ka]=მატარებლების მმართველი KDED
+Name[kk]=KDED ауыстырмалы тасушыларды басқару
+Name[km]=កម្មវិធី​គ្រប់គ្រង​ព័ត៌មាន KDED
+Name[ko]=KDE 창 관리자
+Name[lv]=KDED Datu nesēju menedžeris
+Name[mk]=Менаџер на носачи KDED
+Name[ms]=Pengurus Media KDED
+Name[nb]=KDED mediebehandler
+Name[nds]=KDED-Medienpleeg
+Name[ne]=KDED मिडिया प्रबन्धक
+Name[nl]=KDED-Mediabeheerder
+Name[nn]=KDED Mediehandsamar
+Name[pa]=KDED ਮਾਧਿਅਮ ਮੈਨੇਜਰ
+Name[pl]=Menedżer nośników danych dla KDED
+Name[pt]=Gestor de Dispositivos KDED
+Name[pt_BR]=Gerenciador de Mídia
+Name[ro]=Manager multimedia KDED
+Name[ru]=Управление подключаемыми устройствами
+Name[rw]=Mugenga Igihuza KDED
+Name[se]=KDED-mediagieđahalli
+Name[sk]=KDED správca médií
+Name[sl]=Upravitelj medijev KDED
+Name[sr]=Менаџер медијума, KDED
+Name[sr@Latn]=Menadžer medijuma, KDED
+Name[sv]=KDED-mediahanterare
+Name[ta]=KDED மீடியா மேலாளர்
+Name[te]=కెడిఈడి మాధ్యమ అభికర్త
+Name[th]=เครื่องมือจัดการสื่อบันทึก KDED
+Name[tr]=KDED Ortam Yöneticisi
+Name[tt]=KDED Media İdäräçe
+Name[uk]=Менеджер носіїв інформації для KDED
+Name[uz]=KDED saqlash uskunalarni boshqaruvchi
+Name[uz@cyrillic]=KDED сақлаш ускуналарни бошқарувчи
+Name[vi]=Trình quản lí Ổ lưu trữ KDED
+Name[wa]=Manaedjeu di fitchîs KDED
+Name[zh_CN]=KDED 介质管理器
+Name[zh_TW]=KDED 媒體管理程式
+Comment=Keep track of media activities and allow to (un)mount (media:/)
+Comment[af]=Hou tred van media aktiwiteite en laat die (ont)koppel van 'media:/' toe
+Comment[ar]=يتتبع نشاطات الوسائط و يسمح بتكيبها/إزالة تركيبها (media:/)
+Comment[be]=Вядзе інфармацыю аб медыяносьбітах і дазваляе прымацоўваць/адмацоўваць іх (media:/)
+Comment[bg]=Наблюдение на устройствата и разрешаване на монтиране/демонтиране на (media:/)
+Comment[bn]=কোথায় কী মিডিয়া ব্যবহার করা হচ্ছে খেয়াল রাখুন এবং (আন)মাউন্ট করুন (media:/)
+Comment[bs]=Prati aktivnosti montiranja uređaja za smještaj podataka (media:/)
+Comment[ca]=Fa el seguiment de les activitats dels suports i permet muntar i desmuntar (media:/)
+Comment[cs]=Udržuje přehled o připojených zařízeních
+Comment[csb]=Dozérô zdarzeniów sparłączonëch z mediama pòdôwków ë zezwôlô je (òd)mòntowac (media:/)
+Comment[da]=Hold styr på medieaktiviteter og tillad at (af)montere (media:/)
+Comment[de]=Überwacht Medien-Aktivität und ermöglicht das Einbinden/Lösen von Einbindungen (media:/)
+Comment[el]=Έλεγχος ενεργειών των μέσων και δυνατότητα (από)προσάρτησης (media:/)
+Comment[eo]=Sekvu spurojn de datumportilaj aktivoj kaj permesu (de/sur)meti (media:/)
+Comment[es]=Monitoriza las actividades de los recursos y permite (des)montarlos (media:/)
+Comment[et]=Hoiab silma peal andmekandjate aktiivsusel ja võimaldab neid ühendada/lahutada (media:/)
+Comment[eu]=Montatzeak begiztatzen ditu (media:/) eta desmontatzen uzten du
+Comment[fa]=حفظ رد فعالیتهای رسانه و اجازۀ سوار(پیاده) کردن (media:/)
+Comment[fi]=Pidä kirjaa tallennustapahtumista ja salli tallennusvälineen liittäminen/irrotus (devices:/)
+Comment[fr]=Gardez une trace des montages et permettre le (dé)montage (media:/)
+Comment[fy]=Hâld de media-aktiviteiten by en stien ta om media oan- en ôf te keppelje (media:/)
+Comment[gl]=Seguemento das actividades dos meios e permite-lle (des)montar (media:/)
+Comment[he]=מנטר אחר פעילויות מדיה, ומאפשר לחבר או לנתק התקנים (media:/)
+Comment[hi]=मीडिया क्रियाओं की जानकारी रखे तथा (अन)माउन्ट करने दे (मीडिया:/)
+Comment[hr]=Praćenje aktivnosti medija i omogućavanje pristupanja i napuštanja
+Comment[hu]=Az adathordozók követése, csatlakoztatása és leválasztása (media:/)
+Comment[is]=Fylgjast með breytingum á tækjum og bjóða upp á (af)tengingu (media:/)
+Comment[it]=Tiene traccia delle attività dei supporti e permette di montarli o smontarli (device:/)
+Comment[ja]=メディアの活動を追跡し、(media:/) をマウントしたりアンマウントします
+Comment[ka]=თვალყურს ადევნებს მედიის აქტიურობას და საშუალებას აძლევს (დე)მონტირების გაკეთებას (media:/)
+Comment[kk]=Тасушылардың белсендігін байқап тіркеуге не тіркеуден шығаруға мүмкіндік береді: (un)mount (media:/)
+Comment[km]=តាមដាន​សកម្មភាព​ព័ត៌មាន និង​អនុញ្ញាត​ឲ្យ​រៀបចំ (មិន​រៀបចំ) (media:/)
+Comment[lt]=Stebi laikmenose vykdomus veiksmus ir leidžia (iš)montuoti (media:/)
+Comment[lv]=Seko datu nesēju aktivitātēm un ļauj montēt/nomontēt tos (media:/)
+Comment[mk]=Води сметка за активностите на носачите и дозволува (од)монтирање (media:/)
+Comment[ms]=Ikuti perkembangan aktiviti media dan benarkan untuk (nyah)lekap (media:/)
+Comment[mt]=Żomm kont ta' attivitajiet ta' mmuntar u ippermetti (un)mount (media:/)
+Comment[nb]=Holder styr på monteringsaktiviteter og lar deg (av)montere (media:/)
+Comment[nds]=Blifft bi all Medienaktiviteten op'n Stand un verlöövt dat In- un Afhangen (media:/)
+Comment[ne]=मिडिया क्रियाकलापको मार्ग राख्नुहोस् र (अन)माउन्ट (media:/) गर्न अनुमति दिनुहोस्
+Comment[nl]=Houdt de media-activiteiten bij en staat u toe om media aan- en af te koppelen (media:/)
+Comment[nn]=Held styr på medieaktivitetar og lèt deg montera og avmontera (media:/)
+Comment[pa]=ਮਾਊਟ ਕਾਰਵਾਈਆਂ ਦੀ ਜਾਣਕਾਰੀ ਰੱਖੋ ਅਤੇ ਅਨ-ਮਾਊਟ ਕਰਨ ਦਿਓ (ਜੰਤਰ:/)
+Comment[pl]=Śledzi zdarzenia związane z nośnikami danych i pozwala je (od)montować (media:/)
+Comment[pt]=Manter o registo das actividades de dispositivos e permitir a (des)montagem (media:/)
+Comment[pt_BR]=Monitora as atividades de mídias e permite a (des)montagem (media:/)
+Comment[ro]=Urmărește activitățile multimedia și permite (de)montarea media:/
+Comment[ru]=Автоматическое подключение устройств (media:/)
+Comment[rw]=Kugumana inzira y'ibikorwa by'ibitangazamakuru no kwemerera gushyiramo(gukuramo) (ibitangazamakuru:/)
+Comment[se]=Gozit mii dáhpáhuvvá median ja diktá du gálgat ja čadnat daid (media:/)
+Comment[sk]=Sledovanie pripojenia/odpojenia medií (media:/)
+Comment[sl]=Nadzoruj dejanja medija in dovilo priklop/odklop (media:/)
+Comment[sr]=Прати активност медијума и омогућава (де)монтирање (media:/)
+Comment[sr@Latn]=Prati aktivnost medijuma i omogućava (de)montiranje (media:/)
+Comment[sv]=Håll reda på mediaaktiviteter och tillåt (av)montering (media:/)
+Comment[ta]=இடைக்காலத்திற்குரிய நடவடிக்கைகளின் வைத்திரு. (சாதனம்:/)த்தை ஏற்ற(இறக்க)கவும் அனுமதி
+Comment[th]=จะคอยติดตามกิจกรรมของสื่อบันทึก และอนุญาตให้เมานท์หรือยกเลิกการเมานท์ (media:/)
+Comment[tr]=Ortam işlemlerini takip et ve bağlanma işlemlerine izin ver(media:/)
+Comment[tt]=Cıhazlarnıñ totaşuın/ayırıluın sizüçe närsä (media:/)
+Comment[uk]=Спостерігає за змінами серед носіїв інформації та дозволяє (роз)монтування (media:/)
+Comment[vi]=Theo dõi các hoạt động của ổ lưu trữ và cho phép lắp đặt hay gỡ bỏ chúng ở thư mục "media:/"
+Comment[wa]=Wåde li trace des activités media eyet permete di (dis)monter (media:/)
+Comment[zh_CN]=跟踪介质活动并允许挂载或卸载(media:/)
+Comment[zh_TW]=持續追蹤媒體活動並允許(解除)掛載 (media:/)
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=mediamanager
+X-KDE-FactoryName=mediamanager
+X-KDE-Kded-autoload=true
+X-KDE-Kded-load-on-demand=true
+X-KDE-Kded-phase=1
diff --git a/kioslave/media/mediamanager/mediamanager.h b/kioslave/media/mediamanager/mediamanager.h
new file mode 100644
index 000000000..1e5aa1d84
--- /dev/null
+++ b/kioslave/media/mediamanager/mediamanager.h
@@ -0,0 +1,90 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _MEDIAMANAGER_H_
+#define _MEDIAMANAGER_H_
+
+#include <kdedmodule.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "medialist.h"
+#include "backendbase.h"
+#include "removablebackend.h"
+#include "mediadirnotify.h"
+
+class HALBackend;
+class FstabBackend;
+
+class MediaManager : public KDEDModule
+{
+Q_OBJECT
+K_DCOP
+public:
+ MediaManager(const QCString &obj);
+ ~MediaManager();
+
+k_dcop:
+ QStringList fullList();
+ QStringList properties(const QString &name);
+ QStringList mountoptions(const QString &name);
+ bool setMountoptions(const QString &name, const QStringList &options);
+
+ QString mount(const QString &uid);
+ QString unmount(const QString &uid);
+
+ QString nameForLabel(const QString &label);
+ ASYNC setUserLabel(const QString &name, const QString &label);
+
+ ASYNC reloadBackends();
+
+ // Removable media handling (for people not having HAL)
+ bool removablePlug(const QString &devNode, const QString &label);
+ bool removableUnplug(const QString &devNode);
+ bool removableCamera(const QString &devNode);
+
+k_dcop_signals:
+ void mediumAdded(const QString &name, bool allowNotification);
+ void mediumRemoved(const QString &name, bool allowNotification);
+ void mediumChanged(const QString &name, bool allowNotification);
+
+ // For compatibility purpose, not needed for KDE4
+ void mediumAdded(const QString &name);
+ void mediumRemoved(const QString &name);
+ void mediumChanged(const QString &name);
+
+private slots:
+ void loadBackends();
+
+ void slotMediumAdded(const QString &id, const QString &name,
+ bool allowNotification);
+ void slotMediumRemoved(const QString &id, const QString &name,
+ bool allowNotification);
+ void slotMediumChanged(const QString &id, const QString &name,
+ bool mounted, bool allowNotification);
+
+private:
+ MediaList m_mediaList;
+ QValueList<BackendBase*> m_backends;
+ RemovableBackend *mp_removableBackend;
+ HALBackend *m_halbackend;
+ MediaDirNotify m_dirNotify;
+ FstabBackend *m_fstabbackend;
+};
+
+#endif
diff --git a/kioslave/media/mediamanager/removablebackend.cpp b/kioslave/media/mediamanager/removablebackend.cpp
new file mode 100644
index 000000000..ea8318ecf
--- /dev/null
+++ b/kioslave/media/mediamanager/removablebackend.cpp
@@ -0,0 +1,180 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kévin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "removablebackend.h"
+
+#include <klocale.h>
+#include <kdirwatch.h>
+#include <kurl.h>
+#include <kmountpoint.h>
+#include <kstandarddirs.h>
+
+#ifdef _OS_SOLARIS_
+#define MTAB "/etc/mnttab"
+#else
+#define MTAB "/etc/mtab"
+#endif
+
+
+
+RemovableBackend::RemovableBackend(MediaList &list)
+ : QObject(), BackendBase(list)
+{
+ KDirWatch::self()->addFile(MTAB);
+
+ connect( KDirWatch::self(), SIGNAL( dirty(const QString&) ),
+ this, SLOT( slotDirty(const QString&) ) );
+ KDirWatch::self()->startScan();
+}
+
+RemovableBackend::~RemovableBackend()
+{
+ QStringList::iterator it = m_removableIds.begin();
+ QStringList::iterator end = m_removableIds.end();
+
+ for (; it!=end; ++it)
+ {
+ m_mediaList.removeMedium(*it, false);
+ }
+
+ KDirWatch::self()->removeFile(MTAB);
+}
+
+bool RemovableBackend::plug(const QString &devNode, const QString &label)
+{
+ QString name = generateName(devNode);
+ QString id = generateId(devNode);
+
+ if (!m_removableIds.contains(id))
+ {
+ Medium *medium = new Medium(id, name);
+ medium->mountableState(devNode, QString::null,
+ QString::null, false);
+
+ QStringList words = QStringList::split(" ", label);
+
+ QStringList::iterator it = words.begin();
+ QStringList::iterator end = words.end();
+
+ QString tmp = (*it).lower();
+ tmp[0] = tmp[0].upper();
+ QString new_label = tmp;
+
+ ++it;
+ for (; it!=end; ++it)
+ {
+ tmp = (*it).lower();
+ tmp[0] = tmp[0].upper();
+ new_label+= " "+tmp;
+ }
+
+ medium->setLabel(new_label);
+ medium->setMimeType("media/removable_unmounted");
+
+ m_removableIds.append(id);
+ return !m_mediaList.addMedium(medium).isNull();
+ }
+ return false;
+}
+
+bool RemovableBackend::unplug(const QString &devNode)
+{
+ QString id = generateId(devNode);
+ if (m_removableIds.contains(id))
+ {
+ m_removableIds.remove(id);
+ return m_mediaList.removeMedium(id);
+ }
+ return false;
+}
+
+bool RemovableBackend::camera(const QString &devNode)
+{
+ QString id = generateId(devNode);
+ if (m_removableIds.contains(id))
+ {
+ return m_mediaList.changeMediumState(id,
+ QString("camera:/"), false, "media/gphoto2camera");
+ }
+ return false;
+}
+
+void RemovableBackend::slotDirty(const QString &path)
+{
+ if (path==MTAB)
+ {
+ handleMtabChange();
+ }
+}
+
+
+void RemovableBackend::handleMtabChange()
+{
+ QStringList new_mtabIds;
+ KMountPoint::List mtab = KMountPoint::currentMountPoints();
+
+ KMountPoint::List::iterator it = mtab.begin();
+ KMountPoint::List::iterator end = mtab.end();
+
+ for (; it!=end; ++it)
+ {
+ QString dev = (*it)->mountedFrom();
+ QString mp = (*it)->mountPoint();
+ QString fs = (*it)->mountType();
+
+ QString id = generateId(dev);
+ new_mtabIds+=id;
+
+ if ( !m_mtabIds.contains(id)
+ && m_removableIds.contains(id) )
+ {
+ m_mediaList.changeMediumState(id, dev, mp, fs, true,
+ false, "media/removable_mounted");
+ }
+ }
+
+ QStringList::iterator it2 = m_mtabIds.begin();
+ QStringList::iterator end2 = m_mtabIds.end();
+
+ for (; it2!=end2; ++it2)
+ {
+ if ( !new_mtabIds.contains(*it2)
+ && m_removableIds.contains(*it2) )
+ {
+ m_mediaList.changeMediumState(*it2, false,
+ false, "media/removable_unmounted");
+ }
+ }
+
+ m_mtabIds = new_mtabIds;
+}
+
+QString RemovableBackend::generateId(const QString &devNode)
+{
+ QString dev = KStandardDirs::realFilePath(devNode);
+
+ return "/org/kde/mediamanager/removable/"
+ +dev.replace("/", "");
+}
+
+QString RemovableBackend::generateName(const QString &devNode)
+{
+ return KURL(devNode).fileName();
+}
+
+#include "removablebackend.moc"
diff --git a/kioslave/media/mediamanager/removablebackend.h b/kioslave/media/mediamanager/removablebackend.h
new file mode 100644
index 000000000..02fc0409e
--- /dev/null
+++ b/kioslave/media/mediamanager/removablebackend.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2004 Kvin Ottens <ervin ipsquad net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _REMOVABLEBACKEND_H_
+#define _REMOVABLEBACKEND_H_
+
+#include "backendbase.h"
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+class RemovableBackend : public QObject, public BackendBase
+{
+Q_OBJECT
+
+public:
+ RemovableBackend(MediaList &list);
+ virtual ~RemovableBackend();
+
+ bool plug(const QString &devNode, const QString &label);
+ bool unplug(const QString &devNode);
+ bool camera(const QString &devNode);
+
+private slots:
+ void slotDirty(const QString &path);
+
+private:
+ void handleMtabChange();
+
+ static QString generateId(const QString &devNode);
+ static QString generateName(const QString &devNode);
+
+ QStringList m_removableIds;
+ QStringList m_mtabIds;
+};
+
+#endif