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