1
/* This file is part of the KDE Project
2
Copyright (c) 2005 Jean-Remy Falleri <jr.falleri@laposte.net>
3
Copyright (c) 2005 Kévin Ottens <ervin ipsquad net>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License version 2 as published by the Free Software Foundation.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301, USA.
20
#include "medianotifier.h"
23
#include <qfileinfo.h>
25
#include <kapplication.h>
31
#include <kmessagebox.h>
32
#include <kstdguiitem.h>
33
#include <kstandarddirs.h>
35
#include "notificationdialog.h"
36
#include "notifiersettings.h"
37
#include "notifieraction.h"
38
#include "mediamanagersettings.h"
40
MediaNotifier::MediaNotifier(const QCString &name) : KDEDModule(name)
42
connectDCOPSignal( "kded", "mediamanager", "mediumAdded(QString, bool)",
43
"onMediumChange(QString, bool)", true );
45
connectDCOPSignal( "kded", "mediamanager", "mediumChanged(QString, bool)",
46
"onMediumChange(QString, bool)", true );
49
MediaNotifier::~MediaNotifier()
51
disconnectDCOPSignal( "kded", "mediamanager", "mediumAdded(QString, bool)",
52
"onMediumChange(QString, bool)" );
54
disconnectDCOPSignal( "kded", "mediamanager", "mediumChanged(QString, bool)",
55
"onMediumChange(QString, bool)" );
58
void MediaNotifier::onMediumChange( const QString &name, bool allowNotification )
60
kdDebug() << "MediaNotifier::onMediumChange( " << name << ", "
61
<< allowNotification << ")" << endl;
63
if ( !allowNotification )
66
// Update user activity timestamp, otherwise the notification dialog will be shown
67
// in the background due to focus stealing prevention. Entering a new media can
68
// be seen as a kind of user activity after all. It'd be better to update the timestamp
69
// as soon as the media is entered, but it apparently takes some time to get here.
70
kapp->updateUserTimestamp();
72
KURL url( "system:/media/"+name );
74
KIO::SimpleJob *job = KIO::stat( url, false );
75
job->setInteractive( false );
77
m_allowNotificationMap[job] = allowNotification;
79
connect( job, SIGNAL( result( KIO::Job * ) ),
80
this, SLOT( slotStatResult( KIO::Job * ) ) );
83
void MediaNotifier::slotStatResult( KIO::Job *job )
85
bool allowNotification = m_allowNotificationMap[job];
86
m_allowNotificationMap.remove( job );
88
if ( job->error() != 0 ) return;
90
KIO::StatJob *stat_job = static_cast<KIO::StatJob *>( job );
92
KIO::UDSEntry entry = stat_job->statResult();
93
KURL url = stat_job->url();
95
KFileItem medium( entry, url );
97
if ( autostart( medium ) ) return;
99
if ( allowNotification ) notify( medium );
102
bool MediaNotifier::autostart( const KFileItem &medium )
104
QString mimetype = medium.mimetype();
106
bool is_cdrom = mimetype.startsWith( "cd" ) || mimetype.startsWith( "dvd" );
107
bool is_mounted = mimetype.endsWith( "_mounted" );
109
// We autorun only on CD/DVD or removable disks (USB, Firewire)
110
if ( !( is_cdrom || is_mounted )
111
&& mimetype!="media/removable_mounted" )
117
// Here starts the 'Autostart Of Applications After Mount' implementation
119
// The desktop environment MAY ignore Autostart files altogether
120
// based on policy set by the user, system administrator or vendor.
121
MediaManagerSettings::self()->readConfig();
122
if ( !MediaManagerSettings::self()->autostartEnabled() )
127
// From now we're sure the medium is already mounted.
128
// We can use the local path for stating, no need to use KIO here.
130
QString path = medium.mostLocalURL( local ).path(); // local is always true here...
132
// When a new medium is mounted the root directory of the medium should
133
// be checked for the following Autostart files in order of precedence:
134
// .autorun, autorun, autorun.sh
135
QStringList autorun_list;
136
autorun_list << ".autorun" << "autorun" << "autorun.sh";
138
QStringList::iterator it = autorun_list.begin();
139
QStringList::iterator end = autorun_list.end();
141
for ( ; it!=end; ++it )
143
if ( QFile::exists( path + "/" + *it ) )
145
return execAutorun( medium, path, *it );
149
// When a new medium is mounted the root directory of the medium should
150
// be checked for the following Autoopen files in order of precedence:
151
// .autoopen, autoopen
152
QStringList autoopen_list;
153
autoopen_list << ".autoopen" << "autoopen";
155
it = autoopen_list.begin();
156
end = autoopen_list.end();
158
for ( ; it!=end; ++it )
160
if ( QFile::exists( path + "/" + *it ) )
162
return execAutoopen( medium, path, *it );
169
bool MediaNotifier::execAutorun( const KFileItem &medium, const QString &path,
170
const QString &autorunFile )
172
// The desktop environment MUST prompt the user for confirmation
173
// before automatically starting an application.
174
QString mediumType = medium.mimeTypePtr()->name();
175
QString text = i18n( "An autorun file has been found on your '%1'."
176
" Do you want to execute it?\n"
177
"Note that executing a file on a medium may compromise"
178
" your system's security").arg( mediumType );
179
QString caption = i18n( "Autorun - %1" ).arg( medium.url().prettyURL() );
180
KGuiItem yes = KStdGuiItem::yes();
181
KGuiItem no = KStdGuiItem::no();
182
int options = KMessageBox::Notify | KMessageBox::Dangerous;
184
int answer = KMessageBox::warningYesNo( 0L, text, caption, yes, no,
185
QString::null, options );
187
if ( answer == KMessageBox::Yes )
189
// When an Autostart file has been detected and the user has
190
// confirmed its execution the autostart file MUST be executed
191
// with the current working directory ( CWD ) set to the root
192
// directory of the medium.
194
proc << "sh" << autorunFile;
195
proc.setWorkingDirectory( path );
203
bool MediaNotifier::execAutoopen( const KFileItem &medium, const QString &path,
204
const QString &autoopenFile )
206
// An Autoopen file MUST contain a single relative path that points
207
// to a non-executable file contained on the medium. [...]
208
QFile file( path+"/"+autoopenFile );
209
file.open( IO_ReadOnly );
210
QTextStream stream( &file );
212
QString relative_path = stream.readLine().stripWhiteSpace();
214
// The relative path MUST NOT contain path components that
215
// refer to a parent directory ( ../ )
216
if ( relative_path.startsWith( "/" ) || relative_path.contains( "../" ) )
221
// The desktop environment MUST verify that the relative path points
222
// to a file that is actually located on the medium [...]
223
QString resolved_path
224
= KStandardDirs::realFilePath( path+"/"+relative_path );
226
if ( !resolved_path.startsWith( path ) )
232
QFile document( resolved_path );
234
// TODO: What about FAT all files are executable...
235
// If the relative path points to an executable file then the desktop
236
// environment MUST NOT execute the file.
237
if ( !document.exists() /*|| QFileInfo(document).isExecutable()*/ )
242
KURL url = medium.url();
243
url.addPath( relative_path );
245
// The desktop environment MUST prompt the user for confirmation
246
// before opening the file.
247
QString mediumType = medium.mimeTypePtr()->name();
248
QString filename = url.filename();
249
QString text = i18n( "An autoopen file has been found on your '%1'."
250
" Do you want to open '%2'?\n"
251
"Note that opening a file on a medium may compromise"
252
" your system's security").arg( mediumType ).arg( filename );
253
QString caption = i18n( "Autoopen - %1" ).arg( medium.url().prettyURL() );
254
KGuiItem yes = KStdGuiItem::yes();
255
KGuiItem no = KStdGuiItem::no();
256
int options = KMessageBox::Notify | KMessageBox::Dangerous;
258
int answer = KMessageBox::warningYesNo( 0L, text, caption, yes, no,
259
QString::null, options );
261
// TODO: Take case of the "UNLESS" part?
262
// When an Autoopen file has been detected and the user has confirmed
263
// that the file indicated in the Autoopen file should be opened then
264
// the file indicated in the Autoopen file MUST be opened in the
265
// application normally preferred by the user for files of its kind
266
// UNLESS the user instructed otherwise.
267
if ( answer == KMessageBox::Yes )
269
( void ) new KRun( url );
275
void MediaNotifier::notify( KFileItem &medium )
277
kdDebug() << "Notification triggered." << endl;
279
NotifierSettings *settings = new NotifierSettings();
281
if ( settings->autoActionForMimetype( medium.mimetype() )==0L )
283
QValueList<NotifierAction*> actions
284
= settings->actionsForMimetype( medium.mimetype() );
286
// If only one action remains, it's the "do nothing" action
287
// no need to popup in this case.
288
if ( actions.size()>1 )
290
NotificationDialog *dialog
291
= new NotificationDialog( medium, settings );
297
NotifierAction *action = settings->autoActionForMimetype( medium.mimetype() );
298
action->execute( medium );
305
KDE_EXPORT KDEDModule *create_medianotifier(const QCString &name)
307
KGlobal::locale()->insertCatalogue("kay");
308
return new MediaNotifier(name);
312
#include "medianotifier.moc"