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