summaryrefslogtreecommitdiffstats
path: root/kioslave/media/medianotifier/medianotifier.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kioslave/media/medianotifier/medianotifier.cpp')
-rw-r--r--kioslave/media/medianotifier/medianotifier.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/kioslave/media/medianotifier/medianotifier.cpp b/kioslave/media/medianotifier/medianotifier.cpp
new file mode 100644
index 000000000..98a474ba7
--- /dev/null
+++ b/kioslave/media/medianotifier/medianotifier.cpp
@@ -0,0 +1,312 @@
+/* This file is part of the KDE Project
+ Copyright (c) 2005 Jean-Remy Falleri <jr.falleri@laposte.net>
+ Copyright (c) 2005 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 "medianotifier.h"
+
+#include <qfile.h>
+#include <qfileinfo.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <krun.h>
+#include <kmessagebox.h>
+#include <kstdguiitem.h>
+#include <kstandarddirs.h>
+
+#include "notificationdialog.h"
+#include "notifiersettings.h"
+#include "notifieraction.h"
+#include "mediamanagersettings.h"
+
+MediaNotifier::MediaNotifier(const QCString &name) : KDEDModule(name)
+{
+ connectDCOPSignal( "kded", "mediamanager", "mediumAdded(QString, bool)",
+ "onMediumChange(QString, bool)", true );
+
+ connectDCOPSignal( "kded", "mediamanager", "mediumChanged(QString, bool)",
+ "onMediumChange(QString, bool)", true );
+}
+
+MediaNotifier::~MediaNotifier()
+{
+ disconnectDCOPSignal( "kded", "mediamanager", "mediumAdded(QString, bool)",
+ "onMediumChange(QString, bool)" );
+
+ disconnectDCOPSignal( "kded", "mediamanager", "mediumChanged(QString, bool)",
+ "onMediumChange(QString, bool)" );
+}
+
+void MediaNotifier::onMediumChange( const QString &name, bool allowNotification )
+{
+ kdDebug() << "MediaNotifier::onMediumChange( " << name << ", "
+ << allowNotification << ")" << endl;
+
+ if ( !allowNotification )
+ return;
+
+// Update user activity timestamp, otherwise the notification dialog will be shown
+// in the background due to focus stealing prevention. Entering a new media can
+// be seen as a kind of user activity after all. It'd be better to update the timestamp
+// as soon as the media is entered, but it apparently takes some time to get here.
+ kapp->updateUserTimestamp();
+
+ KURL url( "system:/media/"+name );
+
+ KIO::SimpleJob *job = KIO::stat( url, false );
+ job->setInteractive( false );
+
+ m_allowNotificationMap[job] = allowNotification;
+
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotStatResult( KIO::Job * ) ) );
+}
+
+void MediaNotifier::slotStatResult( KIO::Job *job )
+{
+ bool allowNotification = m_allowNotificationMap[job];
+ m_allowNotificationMap.remove( job );
+
+ if ( job->error() != 0 ) return;
+
+ KIO::StatJob *stat_job = static_cast<KIO::StatJob *>( job );
+
+ KIO::UDSEntry entry = stat_job->statResult();
+ KURL url = stat_job->url();
+
+ KFileItem medium( entry, url );
+
+ if ( autostart( medium ) ) return;
+
+ if ( allowNotification ) notify( medium );
+}
+
+bool MediaNotifier::autostart( const KFileItem &medium )
+{
+ QString mimetype = medium.mimetype();
+
+ bool is_cdrom = mimetype.startsWith( "cd" ) || mimetype.startsWith( "dvd" );
+ bool is_mounted = mimetype.endsWith( "_mounted" );
+
+ // We autorun only on CD/DVD or removable disks (USB, Firewire)
+ if ( !( is_cdrom || is_mounted )
+ && mimetype!="media/removable_mounted" )
+ {
+ return false;
+ }
+
+
+ // Here starts the 'Autostart Of Applications After Mount' implementation
+
+ // The desktop environment MAY ignore Autostart files altogether
+ // based on policy set by the user, system administrator or vendor.
+ MediaManagerSettings::self()->readConfig();
+ if ( !MediaManagerSettings::self()->autostartEnabled() )
+ {
+ return false;
+ }
+
+ // From now we're sure the medium is already mounted.
+ // We can use the local path for stating, no need to use KIO here.
+ bool local;
+ QString path = medium.mostLocalURL( local ).path(); // local is always true here...
+
+ // When a new medium is mounted the root directory of the medium should
+ // be checked for the following Autostart files in order of precedence:
+ // .autorun, autorun, autorun.sh
+ QStringList autorun_list;
+ autorun_list << ".autorun" << "autorun" << "autorun.sh";
+
+ QStringList::iterator it = autorun_list.begin();
+ QStringList::iterator end = autorun_list.end();
+
+ for ( ; it!=end; ++it )
+ {
+ if ( QFile::exists( path + "/" + *it ) )
+ {
+ return execAutorun( medium, path, *it );
+ }
+ }
+
+ // When a new medium is mounted the root directory of the medium should
+ // be checked for the following Autoopen files in order of precedence:
+ // .autoopen, autoopen
+ QStringList autoopen_list;
+ autoopen_list << ".autoopen" << "autoopen";
+
+ it = autoopen_list.begin();
+ end = autoopen_list.end();
+
+ for ( ; it!=end; ++it )
+ {
+ if ( QFile::exists( path + "/" + *it ) )
+ {
+ return execAutoopen( medium, path, *it );
+ }
+ }
+
+ return false;
+}
+
+bool MediaNotifier::execAutorun( const KFileItem &medium, const QString &path,
+ const QString &autorunFile )
+{
+ // The desktop environment MUST prompt the user for confirmation
+ // before automatically starting an application.
+ QString mediumType = medium.mimeTypePtr()->name();
+ QString text = i18n( "An autorun file has been found on your '%1'."
+ " Do you want to execute it?\n"
+ "Note that executing a file on a medium may compromise"
+ " your system's security").arg( mediumType );
+ QString caption = i18n( "Autorun - %1" ).arg( medium.url().prettyURL() );
+ KGuiItem yes = KStdGuiItem::yes();
+ KGuiItem no = KStdGuiItem::no();
+ int options = KMessageBox::Notify | KMessageBox::Dangerous;
+
+ int answer = KMessageBox::warningYesNo( 0L, text, caption, yes, no,
+ QString::null, options );
+
+ if ( answer == KMessageBox::Yes )
+ {
+ // When an Autostart file has been detected and the user has
+ // confirmed its execution the autostart file MUST be executed
+ // with the current working directory ( CWD ) set to the root
+ // directory of the medium.
+ KProcess proc;
+ proc << "sh" << autorunFile;
+ proc.setWorkingDirectory( path );
+ proc.start();
+ proc.detach();
+ }
+
+ return true;
+}
+
+bool MediaNotifier::execAutoopen( const KFileItem &medium, const QString &path,
+ const QString &autoopenFile )
+{
+ // An Autoopen file MUST contain a single relative path that points
+ // to a non-executable file contained on the medium. [...]
+ QFile file( path+"/"+autoopenFile );
+ file.open( IO_ReadOnly );
+ QTextStream stream( &file );
+
+ QString relative_path = stream.readLine().stripWhiteSpace();
+
+ // The relative path MUST NOT contain path components that
+ // refer to a parent directory ( ../ )
+ if ( relative_path.startsWith( "/" ) || relative_path.contains( "../" ) )
+ {
+ return false;
+ }
+
+ // The desktop environment MUST verify that the relative path points
+ // to a file that is actually located on the medium [...]
+ QString resolved_path
+ = KStandardDirs::realFilePath( path+"/"+relative_path );
+
+ if ( !resolved_path.startsWith( path ) )
+ {
+ return false;
+ }
+
+
+ QFile document( resolved_path );
+
+ // TODO: What about FAT all files are executable...
+ // If the relative path points to an executable file then the desktop
+ // environment MUST NOT execute the file.
+ if ( !document.exists() /*|| QFileInfo(document).isExecutable()*/ )
+ {
+ return false;
+ }
+
+ KURL url = medium.url();
+ url.addPath( relative_path );
+
+ // The desktop environment MUST prompt the user for confirmation
+ // before opening the file.
+ QString mediumType = medium.mimeTypePtr()->name();
+ QString filename = url.filename();
+ QString text = i18n( "An autoopen file has been found on your '%1'."
+ " Do you want to open '%2'?\n"
+ "Note that opening a file on a medium may compromise"
+ " your system's security").arg( mediumType ).arg( filename );
+ QString caption = i18n( "Autoopen - %1" ).arg( medium.url().prettyURL() );
+ KGuiItem yes = KStdGuiItem::yes();
+ KGuiItem no = KStdGuiItem::no();
+ int options = KMessageBox::Notify | KMessageBox::Dangerous;
+
+ int answer = KMessageBox::warningYesNo( 0L, text, caption, yes, no,
+ QString::null, options );
+
+ // TODO: Take case of the "UNLESS" part?
+ // When an Autoopen file has been detected and the user has confirmed
+ // that the file indicated in the Autoopen file should be opened then
+ // the file indicated in the Autoopen file MUST be opened in the
+ // application normally preferred by the user for files of its kind
+ // UNLESS the user instructed otherwise.
+ if ( answer == KMessageBox::Yes )
+ {
+ ( void ) new KRun( url );
+ }
+
+ return true;
+}
+
+void MediaNotifier::notify( KFileItem &medium )
+{
+ kdDebug() << "Notification triggered." << endl;
+
+ NotifierSettings *settings = new NotifierSettings();
+
+ if ( settings->autoActionForMimetype( medium.mimetype() )==0L )
+ {
+ QValueList<NotifierAction*> actions
+ = settings->actionsForMimetype( medium.mimetype() );
+
+ // If only one action remains, it's the "do nothing" action
+ // no need to popup in this case.
+ if ( actions.size()>1 )
+ {
+ NotificationDialog *dialog
+ = new NotificationDialog( medium, settings );
+ dialog->show();
+ }
+ }
+ else
+ {
+ NotifierAction *action = settings->autoActionForMimetype( medium.mimetype() );
+ action->execute( medium );
+ delete settings;
+ }
+}
+
+extern "C"
+{
+ KDE_EXPORT KDEDModule *create_medianotifier(const QCString &name)
+ {
+ KGlobal::locale()->insertCatalogue("kay");
+ return new MediaNotifier(name);
+ }
+}
+
+#include "medianotifier.moc"