kio Library API Documentation

kmimetype.cpp

00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 1999 Waldo Bastian <bastian@kde.org> 00003 * David Faure <faure@kde.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License version 2 as published by the Free Software Foundation; 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this library; see the file COPYING.LIB. If not, write to 00016 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 * Boston, MA 02111-1307, USA. 00018 **/ 00019 // $Id: kmimetype.cpp,v 1.193.2.1 2005/04/07 12:39:15 faure Exp $ 00020 00021 #include <config.h> 00022 00023 #include <sys/types.h> 00024 #include <sys/stat.h> 00025 00026 #include <assert.h> 00027 #include <dirent.h> 00028 #include <errno.h> 00029 #include <stddef.h> 00030 #include <unistd.h> 00031 #include <stdlib.h> 00032 00033 #include <kmountpoint.h> 00034 00035 #include <kprotocolinfo.h> 00036 #include <kio/global.h> 00037 #include "kmimetype.h" 00038 #include "kservicetypefactory.h" 00039 #include "kmimemagic.h" 00040 #include "kservice.h" 00041 #include "krun.h" 00042 #include "kautomount.h" 00043 #include <kdirnotify_stub.h> 00044 00045 #include <qstring.h> 00046 #include <qfile.h> 00047 #include <kmessageboxwrapper.h> 00048 00049 #include <dcopclient.h> 00050 #include <dcopref.h> 00051 #include <kapplication.h> 00052 #include <kprocess.h> 00053 #include <kdebug.h> 00054 #include <kdesktopfile.h> 00055 #include <kdirwatch.h> 00056 #include <kiconloader.h> 00057 #include <klocale.h> 00058 #include <ksimpleconfig.h> 00059 #include <kstandarddirs.h> 00060 #include <kurl.h> 00061 #include <ksycoca.h> 00062 #include <kde_file.h> 00063 00064 template class KSharedPtr<KMimeType>; 00065 template class QValueList<KMimeType::Ptr>; 00066 00067 KMimeType::Ptr KMimeType::s_pDefaultType = 0L; 00068 bool KMimeType::s_bChecked = false; 00069 00070 void KMimeType::buildDefaultType() 00071 { 00072 assert ( !s_pDefaultType ); 00073 // Try to find the default type 00074 KServiceType * mime = KServiceTypeFactory::self()-> 00075 findServiceTypeByName( defaultMimeType() ); 00076 00077 if (mime && mime->isType( KST_KMimeType )) 00078 { 00079 s_pDefaultType = KMimeType::Ptr((KMimeType *) mime); 00080 } 00081 else 00082 { 00083 errorMissingMimeType( defaultMimeType() ); 00084 KStandardDirs stdDirs; 00085 QString sDefaultMimeType = stdDirs.resourceDirs("mime").first()+defaultMimeType()+".desktop"; 00086 s_pDefaultType = new KMimeType( sDefaultMimeType, defaultMimeType(), 00087 "unknown", "mime", QStringList() ); 00088 } 00089 } 00090 00091 KMimeType::Ptr KMimeType::defaultMimeTypePtr() 00092 { 00093 if ( !s_pDefaultType ) // we need a default type first 00094 buildDefaultType(); 00095 return s_pDefaultType; 00096 } 00097 00098 // Check for essential mimetypes 00099 void KMimeType::checkEssentialMimeTypes() 00100 { 00101 if ( s_bChecked ) // already done 00102 return; 00103 if ( !s_pDefaultType ) // we need a default type first 00104 buildDefaultType(); 00105 00106 s_bChecked = true; // must be done before building mimetypes 00107 00108 // No Mime-Types installed ? 00109 // Lets do some rescue here. 00110 if ( !KServiceTypeFactory::self()->checkMimeTypes() ) 00111 { 00112 KMessageBoxWrapper::error( 0L, i18n( "No mime types installed." ) ); 00113 return; // no point in going any further 00114 } 00115 00116 if ( KMimeType::mimeType( "inode/directory" ) == s_pDefaultType ) 00117 errorMissingMimeType( "inode/directory" ); 00118 if ( KMimeType::mimeType( "inode/directory-locked" ) == s_pDefaultType ) 00119 errorMissingMimeType( "inode/directory-locked" ); 00120 if ( KMimeType::mimeType( "inode/blockdevice" ) == s_pDefaultType ) 00121 errorMissingMimeType( "inode/blockdevice" ); 00122 if ( KMimeType::mimeType( "inode/chardevice" ) == s_pDefaultType ) 00123 errorMissingMimeType( "inode/chardevice" ); 00124 if ( KMimeType::mimeType( "inode/socket" ) == s_pDefaultType ) 00125 errorMissingMimeType( "inode/socket" ); 00126 if ( KMimeType::mimeType( "inode/fifo" ) == s_pDefaultType ) 00127 errorMissingMimeType( "inode/fifo" ); 00128 if ( KMimeType::mimeType( "application/x-shellscript" ) == s_pDefaultType ) 00129 errorMissingMimeType( "application/x-shellscript" ); 00130 if ( KMimeType::mimeType( "application/x-executable" ) == s_pDefaultType ) 00131 errorMissingMimeType( "application/x-executable" ); 00132 if ( KMimeType::mimeType( "application/x-desktop" ) == s_pDefaultType ) 00133 errorMissingMimeType( "application/x-desktop" ); 00134 } 00135 00136 void KMimeType::errorMissingMimeType( const QString& _type ) 00137 { 00138 QString tmp = i18n( "Could not find mime type\n%1" ).arg( _type ); 00139 00140 KMessageBoxWrapper::sorry( 0, tmp ); 00141 } 00142 00143 KMimeType::Ptr KMimeType::mimeType( const QString& _name ) 00144 { 00145 KServiceType * mime = KServiceTypeFactory::self()->findServiceTypeByName( _name ); 00146 00147 if ( !mime || !mime->isType( KST_KMimeType ) ) 00148 { 00149 // When building ksycoca, findServiceTypeByName doesn't create an object 00150 // but returns one from a dict. 00151 if ( !KSycoca::self()->isBuilding() ) 00152 delete mime; 00153 if ( !s_pDefaultType ) 00154 buildDefaultType(); 00155 return s_pDefaultType; 00156 } 00157 00158 // We got a mimetype 00159 return KMimeType::Ptr((KMimeType *) mime); 00160 } 00161 00162 KMimeType::List KMimeType::allMimeTypes() 00163 { 00164 return KServiceTypeFactory::self()->allMimeTypes(); 00165 } 00166 00167 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode, 00168 bool _is_local_file, bool _fast_mode ) 00169 { 00170 checkEssentialMimeTypes(); 00171 QString path = _url.path(); 00172 00173 if ( !_fast_mode && !_is_local_file && _url.isLocalFile() ) 00174 _is_local_file = true; 00175 00176 if ( !_fast_mode && _is_local_file && (_mode == 0 || _mode == (mode_t)-1) ) 00177 { 00178 KDE_struct_stat buff; 00179 if ( KDE_stat( QFile::encodeName(path), &buff ) != -1 ) 00180 _mode = buff.st_mode; 00181 } 00182 00183 // Look at mode_t first 00184 if ( S_ISDIR( _mode ) ) 00185 { 00186 // Special hack for local files. We want to see whether we 00187 // are allowed to enter the directory 00188 if ( _is_local_file ) 00189 { 00190 if ( access( QFile::encodeName(path), R_OK ) == -1 ) 00191 return mimeType( "inode/directory-locked" ); 00192 } 00193 return mimeType( "inode/directory" ); 00194 } 00195 if ( S_ISCHR( _mode ) ) 00196 return mimeType( "inode/chardevice" ); 00197 if ( S_ISBLK( _mode ) ) 00198 return mimeType( "inode/blockdevice" ); 00199 if ( S_ISFIFO( _mode ) ) 00200 return mimeType( "inode/fifo" ); 00201 if ( S_ISSOCK( _mode ) ) 00202 return mimeType( "inode/socket" ); 00203 // KMimeMagic can do that better for local files 00204 if ( !_is_local_file && S_ISREG( _mode ) && ( _mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) ) 00205 return mimeType( "application/x-executable" ); 00206 00207 QString fileName ( _url.fileName() ); 00208 00209 static const QString& slash = KGlobal::staticQString("/"); 00210 if ( ! fileName.isNull() && !path.endsWith( slash ) ) 00211 { 00212 // Try to find it out by looking at the filename 00213 KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName ); 00214 if ( mime ) 00215 { 00216 // Found something - can we trust it ? (e.g. don't trust *.pl over HTTP, could be anything) 00217 if ( _is_local_file || _url.hasSubURL() || // Explicitly trust suburls 00218 KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) ) 00219 { 00220 if ( _is_local_file && !_fast_mode ) { 00221 if ( mime->patternsAccuracy()<100 ) 00222 { 00223 KMimeMagicResult* result = 00224 KMimeMagic::self()->findFileType( path ); 00225 00226 if ( result && result->isValid() ) 00227 return mimeType( result->mimeType() ); 00228 } 00229 } 00230 00231 return mime; 00232 } 00233 } 00234 00235 static const QString& dotdesktop = KGlobal::staticQString(".desktop"); 00236 static const QString& dotkdelnk = KGlobal::staticQString(".kdelnk"); 00237 static const QString& dotdirectory = KGlobal::staticQString(".directory"); 00238 00239 // Another filename binding, hardcoded, is .desktop: 00240 if ( fileName.endsWith( dotdesktop ) ) 00241 return mimeType( "application/x-desktop" ); 00242 // Another filename binding, hardcoded, is .kdelnk; 00243 // this is preserved for backwards compatibility 00244 if ( fileName.endsWith( dotkdelnk ) ) 00245 return mimeType( "application/x-desktop" ); 00246 // .directory files are detected as x-desktop by mimemagic 00247 // but don't have a Type= entry. Better cheat and say they are text files 00248 if ( fileName == dotdirectory ) 00249 return mimeType( "text/plain" ); 00250 } 00251 00252 if ( !_is_local_file || _fast_mode ) 00253 { 00254 QString def = KProtocolInfo::defaultMimetype( _url ); 00255 if ( !def.isEmpty() && def != defaultMimeType() ) 00256 { 00257 // The protocol says it always returns a given mimetype (e.g. text/html for "man:") 00258 return mimeType( def ); 00259 } 00260 if ( path.endsWith( slash ) || path.isEmpty() ) 00261 { 00262 // We have no filename at all. Maybe the protocol has a setting for 00263 // which mimetype this means (e.g. directory). 00264 // For HTTP (def==defaultMimeType()) we don't assume anything, 00265 // because of redirections (e.g. freshmeat downloads). 00266 if ( def.isEmpty() ) 00267 { 00268 // Assume inode/directory, if the protocol supports listing. 00269 if ( KProtocolInfo::supportsListing( _url ) ) 00270 return mimeType( QString::fromLatin1("inode/directory") ); 00271 else 00272 return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/" 00273 } 00274 } 00275 00276 // No more chances for non local URLs 00277 return defaultMimeTypePtr(); 00278 } 00279 00280 // Do some magic for local files 00281 //kdDebug(7009) << QString("Mime Type finding for '%1'").arg(path) << endl; 00282 KMimeMagicResult* result = KMimeMagic::self()->findFileType( path ); 00283 00284 // If we still did not find it, we must assume the default mime type 00285 if ( !result || !result->isValid() ) 00286 return defaultMimeTypePtr(); 00287 00288 // The mimemagic stuff was successful 00289 return mimeType( result->mimeType() ); 00290 } 00291 00292 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode, 00293 bool _is_local_file, bool _fast_mode, 00294 bool *accurate) 00295 { 00296 KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode); 00297 if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr()); 00298 return mime; 00299 } 00300 00301 KMimeType::Ptr KMimeType::diagnoseFileName(const QString &fileName, QString &pattern) 00302 { 00303 return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern ); 00304 } 00305 00306 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode, bool fast_mode ) 00307 { 00308 KURL u; 00309 u.setPath(path); 00310 return findByURL( u, mode, true, fast_mode ); 00311 } 00312 00313 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy ) 00314 { 00315 KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data); 00316 QString type = (result && result->isValid())? 00317 result->mimeType() : defaultMimeType(); 00318 if (accuracy) 00319 *accuracy = result->accuracy(); 00320 return mimeType( result->mimeType() ); 00321 } 00322 00323 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy ) 00324 { 00325 KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName); 00326 QString type = (result && result->isValid())? 00327 result->mimeType() : defaultMimeType(); 00328 if (accuracy) 00329 *accuracy = result->accuracy(); 00330 return mimeType( result->mimeType() ); 00331 } 00332 00333 #define GZIP_MAGIC1 0x1f 00334 #define GZIP_MAGIC2 0x8b 00335 00336 KMimeType::Format KMimeType::findFormatByFileContent( const QString &fileName ) 00337 { 00338 KMimeType::Format result; 00339 result.compression = Format::NoCompression; 00340 KMimeType::Ptr mime = findByPath(fileName); 00341 if (mime->name() == "application/octet-stream") 00342 mime = findByFileContent(fileName); 00343 00344 result.text = mime->name().startsWith("text/"); 00345 QVariant v = mime->property("X-KDE-text"); 00346 if (v.isValid()) 00347 result.text = v.toBool(); 00348 00349 if (mime->name().startsWith("inode/")) 00350 return result; 00351 00352 QFile f(fileName); 00353 if (f.open(IO_ReadOnly)) 00354 { 00355 unsigned char buf[10+1]; 00356 int l = f.readBlock((char *)buf, 10); 00357 if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2)) 00358 result.compression = Format::GZipCompression; 00359 } 00360 return result; 00361 } 00362 00363 KMimeType::KMimeType( const QString & _fullpath, const QString& _type, const QString& _icon, 00364 const QString& _comment, const QStringList& _patterns ) 00365 : KServiceType( _fullpath, _type, _icon, _comment ) 00366 { 00367 m_lstPatterns = _patterns; 00368 } 00369 00370 KMimeType::KMimeType( const QString & _fullpath ) : KServiceType( _fullpath ) 00371 { 00372 KDesktopFile _cfg( _fullpath, true ); 00373 init ( &_cfg ); 00374 00375 if ( !isValid() ) 00376 kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl; 00377 } 00378 00379 KMimeType::KMimeType( KDesktopFile *config ) : KServiceType( config ) 00380 { 00381 init( config ); 00382 00383 if ( !isValid() ) 00384 kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl; 00385 } 00386 00387 void KMimeType::init( KDesktopFile * config ) 00388 { 00389 config->setDesktopGroup(); 00390 m_lstPatterns = config->readListEntry( "Patterns", ';' ); 00391 00392 // Read the X-KDE-AutoEmbed setting and store it in the properties map 00393 QString XKDEAutoEmbed = QString::fromLatin1("X-KDE-AutoEmbed"); 00394 if ( config->hasKey( XKDEAutoEmbed ) ) 00395 m_mapProps.insert( XKDEAutoEmbed, QVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) ); 00396 00397 QString XKDEText = QString::fromLatin1("X-KDE-text"); 00398 if ( config->hasKey( XKDEText ) ) 00399 m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) ); 00400 00401 QString XKDEIsAlso = QString::fromLatin1("X-KDE-IsAlso"); 00402 if ( config->hasKey( XKDEIsAlso ) ) 00403 m_mapProps.insert( XKDEIsAlso, config->readEntry( XKDEIsAlso ) ); 00404 00405 QString XKDEPatternsAccuracy = QString::fromLatin1("X-KDE-PatternsAccuracy"); 00406 if ( config->hasKey( XKDEPatternsAccuracy ) ) 00407 m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) ); 00408 00409 } 00410 00411 KMimeType::KMimeType( QDataStream& _str, int offset ) : KServiceType( _str, offset ) 00412 { 00413 loadInternal( _str ); // load our specific stuff 00414 } 00415 00416 void KMimeType::load( QDataStream& _str ) 00417 { 00418 KServiceType::load( _str ); 00419 loadInternal( _str ); 00420 } 00421 00422 void KMimeType::loadInternal( QDataStream& _str ) 00423 { 00424 // kdDebug(7009) << "KMimeType::load( QDataStream& ) : loading list of patterns" << endl; 00425 _str >> m_lstPatterns; 00426 } 00427 00428 void KMimeType::save( QDataStream& _str ) 00429 { 00430 KServiceType::save( _str ); 00431 // Warning adding/removing fields here involves a binary incompatible change - update version 00432 // number in ksycoca.h 00433 _str << m_lstPatterns; 00434 } 00435 00436 QVariant KMimeType::property( const QString& _name ) const 00437 { 00438 if ( _name == "Patterns" ) 00439 return QVariant( m_lstPatterns ); 00440 00441 return KServiceType::property( _name ); 00442 } 00443 00444 QStringList KMimeType::propertyNames() const 00445 { 00446 QStringList res = KServiceType::propertyNames(); 00447 res.append( "Patterns" ); 00448 00449 return res; 00450 } 00451 00452 KMimeType::~KMimeType() 00453 { 00454 } 00455 00456 QPixmap KMimeType::pixmap( KIcon::Group _group, int _force_size, int _state, 00457 QString * _path ) const 00458 { 00459 KIconLoader *iconLoader=KGlobal::iconLoader(); 00460 QString iconName=icon( QString::null, false ); 00461 if (!iconLoader->extraDesktopThemesAdded()) 00462 { 00463 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00464 if (!pixmap.isNull() ) return pixmap; 00465 00466 iconLoader->addExtraDesktopThemes(); 00467 } 00468 00469 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00470 } 00471 00472 QPixmap KMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size, 00473 int _state, QString * _path ) const 00474 { 00475 KIconLoader *iconLoader=KGlobal::iconLoader(); 00476 QString iconName=icon( _url, _url.isLocalFile() ); 00477 if (!iconLoader->extraDesktopThemesAdded()) 00478 { 00479 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00480 if (!pixmap.isNull() ) return pixmap; 00481 00482 iconLoader->addExtraDesktopThemes(); 00483 } 00484 00485 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00486 } 00487 00488 QPixmap KMimeType::pixmapForURL( const KURL & _url, mode_t _mode, KIcon::Group _group, 00489 int _force_size, int _state, QString * _path ) 00490 { 00491 KIconLoader *iconLoader=KGlobal::iconLoader(); 00492 QString iconName = iconForURL( _url, _mode ); 00493 00494 if (!iconLoader->extraDesktopThemesAdded()) 00495 { 00496 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00497 if (!pixmap.isNull() ) return pixmap; 00498 00499 iconLoader->addExtraDesktopThemes(); 00500 } 00501 00502 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00503 00504 } 00505 00506 QString KMimeType::iconForURL( const KURL & _url, mode_t _mode ) 00507 { 00508 const KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(), 00509 false /*HACK*/); 00510 static const QString& unknown = KGlobal::staticQString("unknown"); 00511 const QString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() ); 00512 QString i = mimeTypeIcon; 00513 00514 // if we don't find an icon, maybe we can use the one for the protocol 00515 if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr() 00516 // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon 00517 || _url.path().length() <= 1 ) 00518 { 00519 i = favIconForURL( _url ); // maybe there is a favicon? 00520 00521 if ( i.isEmpty() ) 00522 i = KProtocolInfo::icon( _url.protocol() ); 00523 00524 // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder") 00525 if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) ) 00526 i = mimeTypeIcon; 00527 } 00528 return i; 00529 } 00530 00531 QString KMimeType::favIconForURL( const KURL& url ) 00532 { 00533 // this method will be called quite often, so better not read the config 00534 // again and again. 00535 static bool useFavIcons = true; 00536 static bool check = true; 00537 if ( check ) { 00538 check = false; 00539 KConfig *config = KGlobal::config(); 00540 KConfigGroupSaver cs( config, "HTML Settings" ); 00541 useFavIcons = config->readBoolEntry( "EnableFavicon", true ); 00542 } 00543 00544 if ( url.isLocalFile() || !url.protocol().startsWith("http") 00545 || !useFavIcons ) 00546 return QString::null; 00547 00548 DCOPRef kded( "kded", "favicons" ); 00549 DCOPReply result = kded.call( "iconForURL(KURL)", url ); 00550 if ( result.isValid() ) 00551 return result; 00552 00553 return QString::null; 00554 } 00555 00556 QString KMimeType::parentMimeType() const 00557 { 00558 QVariant v = property("X-KDE-IsAlso"); 00559 return v.toString(); 00560 } 00561 00562 bool KMimeType::is( const QString& mimeTypeName ) const 00563 { 00564 if ( name() == mimeTypeName ) 00565 return true; 00566 QString st = parentMimeType(); 00567 //if (st.isEmpty()) kdDebug(7009)<<"Parent mimetype is empty"<<endl; 00568 while ( !st.isEmpty() ) 00569 { 00570 //kdDebug(7009)<<"Checking parent mime type: "<<st<<endl; 00571 KMimeType::Ptr ptr = KMimeType::mimeType( st ); 00572 if (!ptr) return false; //error 00573 if ( ptr->name() == mimeTypeName ) 00574 return true; 00575 st = ptr->parentMimeType(); 00576 } 00577 return false; 00578 } 00579 00580 int KMimeType::patternsAccuracy() const { 00581 QVariant v = property("X-KDE-PatternsAccuracy"); 00582 if (!v.isValid()) return 100; 00583 else 00584 return v.toInt(); 00585 } 00586 00587 00588 /******************************************************* 00589 * 00590 * KFolderType 00591 * 00592 ******************************************************/ 00593 00594 QString KFolderType::icon( const QString& _url, bool _is_local ) const 00595 { 00596 if ( !_is_local || _url.isEmpty() ) 00597 return KMimeType::icon( _url, _is_local ); 00598 00599 return KFolderType::icon( KURL(_url), _is_local ); 00600 } 00601 00602 QString KFolderType::icon( const KURL& _url, bool _is_local ) const 00603 { 00604 if ( !_is_local ) 00605 return KMimeType::icon( _url, _is_local ); 00606 00607 KURL u( _url ); 00608 u.addPath( ".directory" ); 00609 00610 QString icon; 00611 // using KStandardDirs as this one checks for path being 00612 // a file instead of a directory 00613 if ( KStandardDirs::exists( u.path() ) ) 00614 { 00615 KSimpleConfig cfg( u.path(), true ); 00616 cfg.setDesktopGroup(); 00617 icon = cfg.readEntry( "Icon" ); 00618 QString empty_icon = cfg.readEntry( "EmptyIcon" ); 00619 00620 if ( !empty_icon.isEmpty() ) 00621 { 00622 bool isempty = false; 00623 DIR *dp = 0L; 00624 struct dirent *ep; 00625 dp = opendir( QFile::encodeName(_url.path()) ); 00626 if ( dp ) 00627 { 00628 QValueList<QCString> entries; 00629 // Note that readdir isn't guaranteed to return "." and ".." first (#79826) 00630 ep=readdir( dp ); if ( ep ) entries.append( ep->d_name ); 00631 ep=readdir( dp ); if ( ep ) entries.append( ep->d_name ); 00632 if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory 00633 isempty = true; 00634 else { 00635 entries.append( ep->d_name ); 00636 if ( readdir( dp ) == 0 ) { // only three 00637 // check if we got "." ".." and ".directory" 00638 isempty = entries.find( "." ) != entries.end() && 00639 entries.find( ".." ) != entries.end() && 00640 entries.find( ".directory" ) != entries.end(); 00641 } 00642 } 00643 if (!isempty && !strcmp(ep->d_name, ".directory")) 00644 isempty = (readdir(dp) == 0L); 00645 closedir( dp ); 00646 } 00647 00648 if ( isempty ) 00649 return empty_icon; 00650 } 00651 } 00652 00653 if ( icon.isEmpty() ) 00654 return KMimeType::icon( _url, _is_local ); 00655 00656 if ( icon.startsWith( "./" ) ) { 00657 // path is relative with respect to the location 00658 // of the .directory file (#73463) 00659 KURL v( _url ); 00660 v.addPath( icon.mid( 2 ) ); 00661 icon = v.path(); 00662 } 00663 00664 return icon; 00665 } 00666 00667 QString KFolderType::comment( const QString& _url, bool _is_local ) const 00668 { 00669 if ( !_is_local || _url.isEmpty() ) 00670 return KMimeType::comment( _url, _is_local ); 00671 00672 return KFolderType::comment( KURL(_url), _is_local ); 00673 } 00674 00675 QString KFolderType::comment( const KURL& _url, bool _is_local ) const 00676 { 00677 if ( !_is_local ) 00678 return KMimeType::comment( _url, _is_local ); 00679 00680 KURL u( _url ); 00681 u.addPath( ".directory" ); 00682 00683 KSimpleConfig cfg( u.path(), true ); 00684 cfg.setDesktopGroup(); 00685 QString comment = cfg.readEntry( "Comment" ); 00686 if ( comment.isEmpty() ) 00687 return KMimeType::comment( _url, _is_local ); 00688 00689 return comment; 00690 } 00691 00692 /******************************************************* 00693 * 00694 * KDEDesktopMimeType 00695 * 00696 ******************************************************/ 00697 00698 QString KDEDesktopMimeType::icon( const QString& _url, bool _is_local ) const 00699 { 00700 if ( !_is_local || _url.isEmpty() ) 00701 return KMimeType::icon( _url, _is_local ); 00702 00703 KURL u( _url ); 00704 return icon( u, _is_local ); 00705 } 00706 00707 QString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const 00708 { 00709 if ( !_is_local ) 00710 return KMimeType::icon( _url, _is_local ); 00711 00712 KSimpleConfig cfg( _url.path(), true ); 00713 cfg.setDesktopGroup(); 00714 QString icon = cfg.readEntry( "Icon" ); 00715 QString type = cfg.readEntry( "Type" ); 00716 00717 if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for 00718 // backwards compatibility 00719 { 00720 QString unmount_icon = cfg.readEntry( "UnmountIcon" ); 00721 QString dev = cfg.readEntry( "Dev" ); 00722 if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() ) 00723 { 00724 QString mp = KIO::findDeviceMountPoint( dev ); 00725 bool mbSupermount = false; 00726 if ( mp.isNull() ) 00727 { 00728 00729 KMountPoint::List mountPoints = KMountPoint::currentMountPoints(); 00730 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 00731 it != mountPoints.end(); ++it) 00732 { 00733 if( (*it)->mountType()=="supermount" && ((*it)->mountedFrom()==dev)) 00734 { 00735 mbSupermount = true; 00736 break; 00737 } 00738 } 00739 } 00740 00741 // Is the device not mounted ? 00742 if ( mp.isNull() && !mbSupermount ) 00743 return unmount_icon; 00744 } 00745 } else if ( type == "Link" ) { 00746 const QString emptyIcon = cfg.readEntry( "EmptyIcon" ); 00747 if ( !emptyIcon.isEmpty() ) { 00748 const QString u = cfg.readPathEntry( "URL" ); 00749 const KURL url( u ); 00750 if ( url.protocol() == "trash" ) { 00751 // We need to find if the trash is empty, preferrably without using a KIO job. 00752 // So instead kio_trash leaves an entry in its config file for us. 00753 KSimpleConfig trashConfig( "trashrc", true ); 00754 trashConfig.setGroup( "Status" ); 00755 if ( trashConfig.readBoolEntry( "Empty", true ) ) { 00756 return emptyIcon; 00757 } 00758 } 00759 } 00760 } 00761 00762 if ( icon.isEmpty() ) 00763 return KMimeType::icon( _url, _is_local ); 00764 00765 return icon; 00766 } 00767 00768 QPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size, 00769 int _state, QString * _path ) const 00770 { 00771 QString _icon = icon( _url, _url.isLocalFile() ); 00772 QPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group, 00773 _force_size, _state, _path, false ); 00774 if ( pix.isNull() ) 00775 pix = KGlobal::iconLoader()->loadIcon( "unknown", _group, 00776 _force_size, _state, _path, false ); 00777 return pix; 00778 } 00779 00780 QString KDEDesktopMimeType::comment( const QString& _url, bool _is_local ) const 00781 { 00782 if ( !_is_local || _url.isEmpty() ) 00783 return KMimeType::comment( _url, _is_local ); 00784 00785 KURL u( _url ); 00786 return comment( u, _is_local ); 00787 } 00788 00789 QString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const 00790 { 00791 if ( !_is_local ) 00792 return KMimeType::comment( _url, _is_local ); 00793 00794 KSimpleConfig cfg( _url.path(), true ); 00795 cfg.setDesktopGroup(); 00796 QString comment = cfg.readEntry( "Comment" ); 00797 if ( comment.isEmpty() ) 00798 return KMimeType::comment( _url, _is_local ); 00799 00800 return comment; 00801 } 00802 00803 pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local ) 00804 { 00805 // It might be a security problem to run external untrusted desktop 00806 // entry files 00807 if ( !_is_local ) 00808 return 0; 00809 00810 KSimpleConfig cfg( u.path(), true ); 00811 cfg.setDesktopGroup(); 00812 QString type = cfg.readEntry( "Type" ); 00813 if ( type.isEmpty() ) 00814 { 00815 QString tmp = i18n("The desktop entry file %1 " 00816 "has no Type=... entry.").arg(u.path() ); 00817 KMessageBoxWrapper::error( 0, tmp); 00818 return 0; 00819 } 00820 00821 //kdDebug(7009) << "TYPE = " << type.data() << endl; 00822 00823 if ( type == "FSDevice" ) 00824 return runFSDevice( u, cfg ); 00825 else if ( type == "Application" ) 00826 return runApplication( u, u.path() ); 00827 else if ( type == "Link" ) 00828 { 00829 cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon) 00830 return runLink( u, cfg ); 00831 } 00832 else if ( type == "MimeType" ) 00833 return runMimeType( u, cfg ); 00834 00835 00836 QString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type ); 00837 KMessageBoxWrapper::error( 0, tmp); 00838 00839 return 0; 00840 } 00841 00842 pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg ) 00843 { 00844 pid_t retval = 0; 00845 00846 QString dev = cfg.readEntry( "Dev" ); 00847 00848 if ( dev.isEmpty() ) 00849 { 00850 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() ); 00851 KMessageBoxWrapper::error( 0, tmp); 00852 return retval; 00853 } 00854 00855 QString mp = KIO::findDeviceMountPoint( dev ); 00856 if ( mp.isNull() ) 00857 { 00858 KMountPoint::List mountPoints = KMountPoint::currentMountPoints(); 00859 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 00860 it != mountPoints.end(); ++it) 00861 { 00862 if( (*it)->mountType()=="supermount" && ((*it)->mountedFrom()==dev)) 00863 { 00864 mp = (*it)->mountPoint(); 00865 break; 00866 } 00867 } 00868 } 00869 // Is the device already mounted ? 00870 if ( !mp.isNull() ) 00871 { 00872 KURL mpURL; 00873 mpURL.setPath( mp ); 00874 // Open a new window 00875 retval = KRun::runURL( mpURL, QString::fromLatin1("inode/directory") ); 00876 } 00877 else 00878 { 00879 bool ro = cfg.readBoolEntry( "ReadOnly", false ); 00880 QString fstype = cfg.readEntry( "FSType" ); 00881 if ( fstype == "Default" ) // KDE-1 thing 00882 fstype = QString::null; 00883 QString point = cfg.readEntry( "MountPoint" ); 00884 #ifndef Q_WS_WIN 00885 (void) new KAutoMount( ro, fstype, dev, point, _url.path() ); 00886 #endif 00887 retval = -1; // we don't want to return 0, but we don't want to return a pid 00888 } 00889 00890 return retval; 00891 } 00892 00893 pid_t KDEDesktopMimeType::runApplication( const KURL& , const QString & _serviceFile ) 00894 { 00895 KService s( _serviceFile ); 00896 if ( !s.isValid() ) 00897 // The error message was already displayed, so we can just quit here 00898 return 0; 00899 00900 KURL::List lst; 00901 return KRun::run( s, lst ); 00902 } 00903 00904 pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg ) 00905 { 00906 QString u = cfg.readPathEntry( "URL" ); 00907 if ( u.isEmpty() ) 00908 { 00909 QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() ); 00910 KMessageBoxWrapper::error( 0, tmp ); 00911 return 0; 00912 } 00913 00914 KURL url ( u ); 00915 KRun* run = new KRun(url); 00916 00917 // X-KDE-LastOpenedWith holds the service desktop entry name that 00918 // was should be preferred for opening this URL if possible. 00919 // This is used by the Recent Documents menu for instance. 00920 QString lastOpenedWidth = cfg.readEntry( "X-KDE-LastOpenedWith" ); 00921 if ( !lastOpenedWidth.isEmpty() ) 00922 run->setPreferredService( lastOpenedWidth ); 00923 00924 return -1; // we don't want to return 0, but we don't want to return a pid 00925 } 00926 00927 pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & ) 00928 { 00929 // Hmm, can't really use keditfiletype since we might be looking 00930 // at the global file, or at a file not in share/mimelnk... 00931 00932 QStringList args; 00933 args << "openProperties"; 00934 args << url.path(); 00935 00936 int pid; 00937 if ( !KApplication::kdeinitExec("kfmclient", args, 0, &pid) ) 00938 return pid; 00939 00940 KProcess p; 00941 p << "kfmclient" << args; 00942 p.start(KProcess::DontCare); 00943 return p.pid(); 00944 } 00945 00946 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url ) 00947 { 00948 QValueList<Service> result; 00949 00950 if ( !_url.isLocalFile() ) 00951 return result; 00952 00953 KSimpleConfig cfg( _url.path(), true ); 00954 cfg.setDesktopGroup(); 00955 QString type = cfg.readEntry( "Type" ); 00956 00957 if ( type.isEmpty() ) 00958 return result; 00959 00960 if ( type == "FSDevice" ) 00961 { 00962 QString dev = cfg.readEntry( "Dev" ); 00963 if ( dev.isEmpty() ) 00964 { 00965 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() ); 00966 KMessageBoxWrapper::error( 0, tmp); 00967 } 00968 else 00969 { 00970 QString mp = KIO::findDeviceMountPoint( dev ); 00971 bool mbSupermount = false; 00972 if ( mp.isEmpty() ) 00973 { 00974 KMountPoint::List mountPoints = KMountPoint::currentMountPoints(); 00975 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 00976 it != mountPoints.end(); ++it) 00977 { 00978 if( (*it)->mountType()=="supermount" && ((*it)->mountedFrom()==dev)) 00979 { 00980 mbSupermount = true; 00981 break; 00982 } 00983 } 00984 } 00985 if( !mbSupermount ) 00986 { 00987 // not mounted ? 00988 if ( mp.isEmpty() ) 00989 { 00990 Service mount; 00991 mount.m_strName = i18n("Mount"); 00992 mount.m_type = ST_MOUNT; 00993 result.append( mount ); 00994 } 00995 else 00996 { 00997 Service unmount; 00998 #ifdef HAVE_VOLMGT 00999 /* 01000 * Solaris' volume management can only umount+eject 01001 */ 01002 unmount.m_strName = i18n("Eject"); 01003 #else 01004 unmount.m_strName = i18n("Unmount"); 01005 #endif 01006 unmount.m_type = ST_UNMOUNT; 01007 result.append( unmount ); 01008 } 01009 } 01010 } 01011 } 01012 return result; 01013 } 01014 01015 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, bool bLocalFiles ) 01016 { 01017 KSimpleConfig cfg( path, true ); 01018 return userDefinedServices( path, cfg, bLocalFiles ); 01019 } 01020 01021 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, KConfig& cfg, bool bLocalFiles ) 01022 { 01023 QValueList<Service> result; 01024 01025 cfg.setDesktopGroup(); 01026 01027 if ( !cfg.hasKey( "Actions" ) ) 01028 return result; 01029 01030 if ( cfg.hasKey( "TryExec" ) ) 01031 { 01032 QString tryexec = cfg.readPathEntry( "TryExec" ); 01033 QString exe = KStandardDirs::findExe( tryexec ); 01034 if (exe.isEmpty()) { 01035 return result; 01036 } 01037 } 01038 01039 QStringList keys = cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator! 01040 01041 if ( keys.count() == 0 ) 01042 return result; 01043 01044 QStringList::ConstIterator it = keys.begin(); 01045 QStringList::ConstIterator end = keys.end(); 01046 for ( ; it != end; ++it ) 01047 { 01048 //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl; 01049 01050 QString group = *it; 01051 01052 if (group == "_SEPARATOR_") 01053 { 01054 Service s; 01055 result.append(s); 01056 continue; 01057 } 01058 01059 group.prepend( "Desktop Action " ); 01060 01061 bool bInvalidMenu = false; 01062 01063 if ( cfg.hasGroup( group ) ) 01064 { 01065 cfg.setGroup( group ); 01066 01067 if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) ) 01068 bInvalidMenu = true; 01069 else 01070 { 01071 QString exec = cfg.readPathEntry( "Exec" ); 01072 if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") ) 01073 { 01074 Service s; 01075 s.m_strName = cfg.readEntry( "Name" ); 01076 s.m_strIcon = cfg.readEntry( "Icon" ); 01077 s.m_strExec = exec; 01078 s.m_type = ST_USER_DEFINED; 01079 s.m_display = !cfg.readBoolEntry( "NoDisplay" ); 01080 result.append( s ); 01081 } 01082 } 01083 } 01084 else 01085 bInvalidMenu = true; 01086 01087 if ( bInvalidMenu ) 01088 { 01089 QString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it ); 01090 KMessageBoxWrapper::error( 0, tmp ); 01091 } 01092 } 01093 01094 return result; 01095 } 01096 01097 void KDEDesktopMimeType::executeService( const QString& _url, KDEDesktopMimeType::Service& _service ) 01098 { 01099 KURL u; 01100 u.setPath(_url); 01101 KURL::List lst; 01102 lst.append( u ); 01103 executeService( lst, _service ); 01104 } 01105 01106 void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service ) 01107 { 01108 //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl; 01109 01110 if ( _service.m_type == ST_USER_DEFINED ) 01111 { 01112 kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName 01113 << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl; 01114 KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon ); 01115 // The action may update the desktop file. Example: eject unmounts (#5129). 01116 KDirNotify_stub allDirNotify("*", "KDirNotify*"); 01117 allDirNotify.FilesChanged( urls ); 01118 return; 01119 } 01120 else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT ) 01121 { 01122 Q_ASSERT( urls.count() == 1 ); 01123 QString path = urls.first().path(); 01124 //kdDebug(7009) << "MOUNT&UNMOUNT" << endl; 01125 01126 KSimpleConfig cfg( path, true ); 01127 cfg.setDesktopGroup(); 01128 QString dev = cfg.readEntry( "Dev" ); 01129 if ( dev.isEmpty() ) 01130 { 01131 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path ); 01132 KMessageBoxWrapper::error( 0, tmp ); 01133 return; 01134 } 01135 QString mp = KIO::findDeviceMountPoint( dev ); 01136 01137 if ( _service.m_type == ST_MOUNT ) 01138 { 01139 // Already mounted? Strange, but who knows ... 01140 if ( !mp.isEmpty() ) 01141 { 01142 kdDebug(7009) << "ALREADY Mounted" << endl; 01143 return; 01144 } 01145 01146 bool ro = cfg.readBoolEntry( "ReadOnly", false ); 01147 QString fstype = cfg.readEntry( "FSType" ); 01148 if ( fstype == "Default" ) // KDE-1 thing 01149 fstype = QString::null; 01150 QString point = cfg.readEntry( "MountPoint" ); 01151 #ifndef Q_WS_WIN 01152 (void)new KAutoMount( ro, fstype, dev, point, path, false ); 01153 #endif 01154 } 01155 else if ( _service.m_type == ST_UNMOUNT ) 01156 { 01157 // Not mounted? Strange, but who knows ... 01158 if ( mp.isEmpty() ) 01159 return; 01160 01161 #ifndef Q_WS_WIN 01162 (void)new KAutoUnmount( mp, path ); 01163 #endif 01164 } 01165 } 01166 else 01167 assert( 0 ); 01168 } 01169 01170 const QString & KMimeType::defaultMimeType() 01171 { 01172 static const QString & s_strDefaultMimeType = 01173 KGlobal::staticQString( "application/octet-stream" ); 01174 return s_strDefaultMimeType; 01175 } 01176 01177 void KMimeType::virtual_hook( int id, void* data ) 01178 { KServiceType::virtual_hook( id, data ); } 01179 01180 void KFolderType::virtual_hook( int id, void* data ) 01181 { KMimeType::virtual_hook( id, data ); } 01182 01183 void KDEDesktopMimeType::virtual_hook( int id, void* data ) 01184 { KMimeType::virtual_hook( id, data ); } 01185 01186 void KExecMimeType::virtual_hook( int id, void* data ) 01187 { KMimeType::virtual_hook( id, data ); } 01188 01189 #include "kmimetyperesolver.moc" 01190
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:20:26 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003