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.187 2004/03/29 09:43:34 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 <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 ( !def.isEmpty() && def != defaultMimeType() ) 00253 { 00254 // The protocol says it always returns a given mimetype (e.g. text/html for "man:") 00255 return mimeType( def ); 00256 } 00257 if ( path.endsWith( slash ) || path.isEmpty() ) 00258 { 00259 // We have no filename at all. Maybe the protocol has a setting for 00260 // which mimetype this means (e.g. directory). 00261 // For HTTP (def==defaultMimeType()) we don't assume anything, 00262 // because of redirections (e.g. freshmeat downloads). 00263 if ( def.isEmpty() ) 00264 { 00265 // Assume inode/directory, if the protocol supports listing. 00266 if ( KProtocolInfo::supportsListing( _url ) ) 00267 return mimeType( QString::fromLatin1("inode/directory") ); 00268 else 00269 return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/" 00270 } 00271 } 00272 00273 // No more chances for non local URLs 00274 return defaultMimeTypePtr(); 00275 } 00276 00277 // Do some magic for local files 00278 //kdDebug(7009) << QString("Mime Type finding for '%1'").arg(path) << endl; 00279 KMimeMagicResult* result = KMimeMagic::self()->findFileType( path ); 00280 00281 // If we still did not find it, we must assume the default mime type 00282 if ( !result || !result->isValid() ) 00283 return defaultMimeTypePtr(); 00284 00285 // The mimemagic stuff was successful 00286 return mimeType( result->mimeType() ); 00287 } 00288 00289 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode, 00290 bool _is_local_file, bool _fast_mode, 00291 bool *accurate) 00292 { 00293 KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode); 00294 if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr()); 00295 return mime; 00296 } 00297 00298 KMimeType::Ptr KMimeType::diagnoseFileName(const QString &fileName, QString &pattern) 00299 { 00300 return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern ); 00301 } 00302 00303 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode, bool fast_mode ) 00304 { 00305 KURL u; 00306 u.setPath(path); 00307 return findByURL( u, mode, true, fast_mode ); 00308 } 00309 00310 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy ) 00311 { 00312 KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data); 00313 QString type = (result && result->isValid())? 00314 result->mimeType() : defaultMimeType(); 00315 if (accuracy) 00316 *accuracy = result->accuracy(); 00317 return mimeType( result->mimeType() ); 00318 } 00319 00320 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy ) 00321 { 00322 KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName); 00323 QString type = (result && result->isValid())? 00324 result->mimeType() : defaultMimeType(); 00325 if (accuracy) 00326 *accuracy = result->accuracy(); 00327 return mimeType( result->mimeType() ); 00328 } 00329 00330 #define GZIP_MAGIC1 0x1f 00331 #define GZIP_MAGIC2 0x8b 00332 00333 KMimeType::Format KMimeType::findFormatByFileContent( const QString &fileName ) 00334 { 00335 KMimeType::Format result; 00336 result.compression = Format::NoCompression; 00337 KMimeType::Ptr mime = findByPath(fileName); 00338 if (mime->name() == "application/octet-stream") 00339 mime = findByFileContent(fileName); 00340 00341 result.text = mime->name().startsWith("text/"); 00342 QVariant v = mime->property("X-KDE-text"); 00343 if (v.isValid()) 00344 result.text = v.toBool(); 00345 00346 if (mime->name().startsWith("inode/")) 00347 return result; 00348 00349 QFile f(fileName); 00350 if (f.open(IO_ReadOnly)) 00351 { 00352 unsigned char buf[10+1]; 00353 int l = f.readBlock((char *)buf, 10); 00354 if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2)) 00355 result.compression = Format::GZipCompression; 00356 } 00357 return result; 00358 } 00359 00360 KMimeType::KMimeType( const QString & _fullpath, const QString& _type, const QString& _icon, 00361 const QString& _comment, const QStringList& _patterns ) 00362 : KServiceType( _fullpath, _type, _icon, _comment ) 00363 { 00364 m_lstPatterns = _patterns; 00365 } 00366 00367 KMimeType::KMimeType( const QString & _fullpath ) : KServiceType( _fullpath ) 00368 { 00369 KDesktopFile _cfg( _fullpath, true ); 00370 init ( &_cfg ); 00371 00372 if ( !isValid() ) 00373 kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl; 00374 } 00375 00376 KMimeType::KMimeType( KDesktopFile *config ) : KServiceType( config ) 00377 { 00378 init( config ); 00379 00380 if ( !isValid() ) 00381 kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl; 00382 } 00383 00384 void KMimeType::init( KDesktopFile * config ) 00385 { 00386 config->setDesktopGroup(); 00387 m_lstPatterns = config->readListEntry( "Patterns", ';' ); 00388 00389 // Read the X-KDE-AutoEmbed setting and store it in the properties map 00390 QString XKDEAutoEmbed = QString::fromLatin1("X-KDE-AutoEmbed"); 00391 if ( config->hasKey( XKDEAutoEmbed ) ) 00392 m_mapProps.insert( XKDEAutoEmbed, QVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) ); 00393 00394 QString XKDEText = QString::fromLatin1("X-KDE-text"); 00395 if ( config->hasKey( XKDEText ) ) 00396 m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) ); 00397 00398 QString XKDEIsAlso = QString::fromLatin1("X-KDE-IsAlso"); 00399 if ( config->hasKey( XKDEIsAlso ) ) 00400 m_mapProps.insert( XKDEIsAlso, config->readEntry( XKDEIsAlso ) ); 00401 00402 QString XKDEPatternsAccuracy = QString::fromLatin1("X-KDE-PatternsAccuracy"); 00403 if ( config->hasKey( XKDEPatternsAccuracy ) ) 00404 m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) ); 00405 00406 } 00407 00408 KMimeType::KMimeType( QDataStream& _str, int offset ) : KServiceType( _str, offset ) 00409 { 00410 loadInternal( _str ); // load our specific stuff 00411 } 00412 00413 void KMimeType::load( QDataStream& _str ) 00414 { 00415 KServiceType::load( _str ); 00416 loadInternal( _str ); 00417 } 00418 00419 void KMimeType::loadInternal( QDataStream& _str ) 00420 { 00421 // kdDebug(7009) << "KMimeType::load( QDataStream& ) : loading list of patterns" << endl; 00422 _str >> m_lstPatterns; 00423 } 00424 00425 void KMimeType::save( QDataStream& _str ) 00426 { 00427 KServiceType::save( _str ); 00428 // Warning adding/removing fields here involves a binary incompatible change - update version 00429 // number in ksycoca.h 00430 _str << m_lstPatterns; 00431 } 00432 00433 QVariant KMimeType::property( const QString& _name ) const 00434 { 00435 if ( _name == "Patterns" ) 00436 return QVariant( m_lstPatterns ); 00437 00438 return KServiceType::property( _name ); 00439 } 00440 00441 QStringList KMimeType::propertyNames() const 00442 { 00443 QStringList res = KServiceType::propertyNames(); 00444 res.append( "Patterns" ); 00445 00446 return res; 00447 } 00448 00449 KMimeType::~KMimeType() 00450 { 00451 } 00452 00453 QPixmap KMimeType::pixmap( KIcon::Group _group, int _force_size, int _state, 00454 QString * _path ) const 00455 { 00456 KIconLoader *iconLoader=KGlobal::iconLoader(); 00457 QString iconName=icon( QString::null, false ); 00458 if (!iconLoader->extraDesktopThemesAdded()) 00459 { 00460 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00461 if (!pixmap.isNull() ) return pixmap; 00462 00463 iconLoader->addExtraDesktopThemes(); 00464 } 00465 00466 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00467 } 00468 00469 QPixmap KMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size, 00470 int _state, QString * _path ) const 00471 { 00472 KIconLoader *iconLoader=KGlobal::iconLoader(); 00473 QString iconName=icon( _url, _url.isLocalFile() ); 00474 if (!iconLoader->extraDesktopThemesAdded()) 00475 { 00476 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00477 if (!pixmap.isNull() ) return pixmap; 00478 00479 iconLoader->addExtraDesktopThemes(); 00480 } 00481 00482 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00483 } 00484 00485 QPixmap KMimeType::pixmapForURL( const KURL & _url, mode_t _mode, KIcon::Group _group, 00486 int _force_size, int _state, QString * _path ) 00487 { 00488 KIconLoader *iconLoader=KGlobal::iconLoader(); 00489 QString iconName = iconForURL( _url, _mode ); 00490 00491 if (!iconLoader->extraDesktopThemesAdded()) 00492 { 00493 QPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true ); 00494 if (!pixmap.isNull() ) return pixmap; 00495 00496 iconLoader->addExtraDesktopThemes(); 00497 } 00498 00499 return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false ); 00500 00501 } 00502 00503 QString KMimeType::iconForURL( const KURL & _url, mode_t _mode ) 00504 { 00505 KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(), 00506 false /*HACK*/); 00507 static const QString& unknown = KGlobal::staticQString("unknown"); 00508 QString i( mt->icon( _url, _url.isLocalFile() )); 00509 00510 // if we don't find an icon, maybe we can use the one for the protocol 00511 if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr()) { 00512 i = favIconForURL( _url ); // maybe there is a favicon? 00513 00514 if ( i.isEmpty() ) 00515 i = KProtocolInfo::icon( _url.protocol() ); 00516 } 00517 return i; 00518 } 00519 00520 QString KMimeType::favIconForURL( const KURL& url ) 00521 { 00522 // this method will be called quite often, so better not read the config 00523 // again and again. 00524 static bool useFavIcons = true; 00525 static bool check = true; 00526 if ( check ) { 00527 check = false; 00528 KConfig *config = KGlobal::config(); 00529 KConfigGroupSaver cs( config, "HTML Settings" ); 00530 useFavIcons = config->readBoolEntry( "EnableFavicon", true ); 00531 } 00532 00533 if ( url.isLocalFile() || !url.protocol().startsWith("http") 00534 || !useFavIcons ) 00535 return QString::null; 00536 00537 DCOPRef kded( "kded", "favicons" ); 00538 DCOPReply result = kded.call( "iconForURL(KURL)", url ); 00539 if ( result.isValid() ) 00540 return result; 00541 00542 return QString::null; 00543 } 00544 00545 QString KMimeType::parentMimeType() const 00546 { 00547 QVariant v = property("X-KDE-IsAlso"); 00548 return v.toString(); 00549 } 00550 00551 bool KMimeType::is( const QString& mimeTypeName ) const 00552 { 00553 if ( name() == mimeTypeName ) 00554 return true; 00555 QString st = parentMimeType(); 00556 while ( !st.isEmpty() ) 00557 { 00558 KMimeType::Ptr ptr = KMimeType::mimeType( st ); 00559 if (!ptr) return false; //error 00560 if ( ptr->name() == mimeTypeName ) 00561 return true; 00562 st = ptr->parentMimeType(); 00563 } 00564 return false; 00565 } 00566 00567 int KMimeType::patternsAccuracy() const { 00568 QVariant v = property("X-KDE-PatternsAccuracy"); 00569 if (!v.isValid()) return 100; 00570 else 00571 return v.toInt(); 00572 } 00573 00574 00575 /******************************************************* 00576 * 00577 * KFolderType 00578 * 00579 ******************************************************/ 00580 00581 QString KFolderType::icon( const QString& _url, bool _is_local ) const 00582 { 00583 if ( !_is_local || _url.isEmpty() ) 00584 return KMimeType::icon( _url, _is_local ); 00585 00586 return KFolderType::icon( KURL(_url), _is_local ); 00587 } 00588 00589 QString KFolderType::icon( const KURL& _url, bool _is_local ) const 00590 { 00591 if ( !_is_local ) 00592 return KMimeType::icon( _url, _is_local ); 00593 00594 KURL u( _url ); 00595 u.addPath( ".directory" ); 00596 00597 QString icon; 00598 // using KStandardDirs as this one checks for path being 00599 // a file instead of a directory 00600 if ( KStandardDirs::exists( u.path() ) ) 00601 { 00602 KSimpleConfig cfg( u.path(), true ); 00603 cfg.setDesktopGroup(); 00604 icon = cfg.readEntry( "Icon" ); 00605 QString empty_icon = cfg.readEntry( "EmptyIcon" ); 00606 00607 if ( !empty_icon.isEmpty() ) 00608 { 00609 bool isempty = false; 00610 DIR *dp = 0L; 00611 struct dirent *ep; 00612 dp = opendir( QFile::encodeName(_url.path()) ); 00613 if ( dp ) 00614 { 00615 ep=readdir( dp ); 00616 ep=readdir( dp ); // ignore '.' and '..' dirent 00617 if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory 00618 isempty = true; 00619 // if third file is .directory and no fourth file -> empty directory 00620 if (!isempty && !strcmp(ep->d_name, ".directory")) 00621 isempty = (readdir(dp) == 0L); 00622 closedir( dp ); 00623 } 00624 00625 if ( isempty ) 00626 return empty_icon; 00627 } 00628 } 00629 00630 if ( icon.isEmpty() ) 00631 return KMimeType::icon( _url, _is_local ); 00632 00633 if ( icon.startsWith( "./" ) ) { 00634 // path is relative with respect to the location 00635 // of the .directory file (#73463) 00636 KURL v( _url ); 00637 v.addPath( icon.mid( 2 ) ); 00638 icon = v.path(); 00639 } 00640 00641 return icon; 00642 } 00643 00644 QString KFolderType::comment( const QString& _url, bool _is_local ) const 00645 { 00646 if ( !_is_local || _url.isEmpty() ) 00647 return KMimeType::comment( _url, _is_local ); 00648 00649 return KFolderType::comment( KURL(_url), _is_local ); 00650 } 00651 00652 QString KFolderType::comment( const KURL& _url, bool _is_local ) const 00653 { 00654 if ( !_is_local ) 00655 return KMimeType::comment( _url, _is_local ); 00656 00657 KURL u( _url ); 00658 u.addPath( ".directory" ); 00659 00660 KSimpleConfig cfg( u.path(), true ); 00661 cfg.setDesktopGroup(); 00662 QString comment = cfg.readEntry( "Comment" ); 00663 if ( comment.isEmpty() ) 00664 return KMimeType::comment( _url, _is_local ); 00665 00666 return comment; 00667 } 00668 00669 /******************************************************* 00670 * 00671 * KDEDesktopMimeType 00672 * 00673 ******************************************************/ 00674 00675 QString KDEDesktopMimeType::icon( const QString& _url, bool _is_local ) const 00676 { 00677 if ( !_is_local || _url.isEmpty() ) 00678 return KMimeType::icon( _url, _is_local ); 00679 00680 KURL u( _url ); 00681 return icon( u, _is_local ); 00682 } 00683 00684 QString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const 00685 { 00686 if ( !_is_local ) 00687 return KMimeType::icon( _url, _is_local ); 00688 00689 KSimpleConfig cfg( _url.path(), true ); 00690 cfg.setDesktopGroup(); 00691 QString icon = cfg.readEntry( "Icon" ); 00692 QString type = cfg.readEntry( "Type" ); 00693 00694 if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for 00695 // backwards compatibility 00696 { 00697 QString unmount_icon = cfg.readEntry( "UnmountIcon" ); 00698 QString dev = cfg.readEntry( "Dev" ); 00699 if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() ) 00700 { 00701 QString mp = KIO::findDeviceMountPoint( dev ); 00702 // Is the device not mounted ? 00703 if ( mp.isNull() ) 00704 return unmount_icon; 00705 } 00706 } 00707 00708 if ( icon.isEmpty() ) 00709 return KMimeType::icon( _url, _is_local ); 00710 00711 return icon; 00712 } 00713 00714 QPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size, 00715 int _state, QString * _path ) const 00716 { 00717 QString _icon = icon( _url, _url.isLocalFile() ); 00718 QPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group, 00719 _force_size, _state, _path, false ); 00720 if ( pix.isNull() ) 00721 pix = KGlobal::iconLoader()->loadIcon( "unknown", _group, 00722 _force_size, _state, _path, false ); 00723 return pix; 00724 } 00725 00726 QString KDEDesktopMimeType::comment( const QString& _url, bool _is_local ) const 00727 { 00728 if ( !_is_local || _url.isEmpty() ) 00729 return KMimeType::comment( _url, _is_local ); 00730 00731 KURL u( _url ); 00732 return comment( u, _is_local ); 00733 } 00734 00735 QString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const 00736 { 00737 if ( !_is_local ) 00738 return KMimeType::comment( _url, _is_local ); 00739 00740 KSimpleConfig cfg( _url.path(), true ); 00741 cfg.setDesktopGroup(); 00742 QString comment = cfg.readEntry( "Comment" ); 00743 if ( comment.isEmpty() ) 00744 return KMimeType::comment( _url, _is_local ); 00745 00746 return comment; 00747 } 00748 00749 pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local ) 00750 { 00751 // It might be a security problem to run external untrusted desktop 00752 // entry files 00753 if ( !_is_local ) 00754 return 0; 00755 00756 KSimpleConfig cfg( u.path(), true ); 00757 cfg.setDesktopGroup(); 00758 QString type = cfg.readEntry( "Type" ); 00759 if ( type.isEmpty() ) 00760 { 00761 QString tmp = i18n("The desktop entry file %1 " 00762 "has no Type=... entry.").arg(u.path() ); 00763 KMessageBoxWrapper::error( 0, tmp); 00764 return 0; 00765 } 00766 00767 //kdDebug(7009) << "TYPE = " << type.data() << endl; 00768 00769 if ( type == "FSDevice" ) 00770 return runFSDevice( u, cfg ); 00771 else if ( type == "Application" ) 00772 return runApplication( u, u.path() ); 00773 else if ( type == "Link" ) 00774 { 00775 cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon) 00776 return runLink( u, cfg ); 00777 } 00778 else if ( type == "MimeType" ) 00779 return runMimeType( u, cfg ); 00780 00781 00782 QString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type ); 00783 KMessageBoxWrapper::error( 0, tmp); 00784 00785 return 0; 00786 } 00787 00788 pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg ) 00789 { 00790 pid_t retval = 0; 00791 00792 QString dev = cfg.readEntry( "Dev" ); 00793 00794 if ( dev.isEmpty() ) 00795 { 00796 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() ); 00797 KMessageBoxWrapper::error( 0, tmp); 00798 return retval; 00799 } 00800 00801 QString mp = KIO::findDeviceMountPoint( dev ); 00802 // Is the device already mounted ? 00803 if ( !mp.isNull() ) 00804 { 00805 KURL mpURL; 00806 mpURL.setPath( mp ); 00807 // Open a new window 00808 retval = KRun::runURL( mpURL, QString::fromLatin1("inode/directory") ); 00809 } 00810 else 00811 { 00812 bool ro = cfg.readBoolEntry( "ReadOnly", false ); 00813 QString fstype = cfg.readEntry( "FSType" ); 00814 if ( fstype == "Default" ) // KDE-1 thing 00815 fstype = QString::null; 00816 QString point = cfg.readEntry( "MountPoint" ); 00817 (void) new KAutoMount( ro, fstype, dev, point, _url.path() ); 00818 retval = -1; // we don't want to return 0, but we don't want to return a pid 00819 } 00820 00821 return retval; 00822 } 00823 00824 pid_t KDEDesktopMimeType::runApplication( const KURL& , const QString & _serviceFile ) 00825 { 00826 KService s( _serviceFile ); 00827 if ( !s.isValid() ) 00828 // The error message was already displayed, so we can just quit here 00829 return 0; 00830 00831 KURL::List lst; 00832 return KRun::run( s, lst ); 00833 } 00834 00835 pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg ) 00836 { 00837 QString u = cfg.readPathEntry( "URL" ); 00838 if ( u.isEmpty() ) 00839 { 00840 QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() ); 00841 KMessageBoxWrapper::error( 0, tmp ); 00842 return 0; 00843 } 00844 00845 KURL url ( u ); 00846 KRun* run = new KRun(url); 00847 00848 // X-KDE-LastOpenedWith holds the service desktop entry name that 00849 // was should be preferred for opening this URL if possible. 00850 // This is used by the Recent Documents menu for instance. 00851 QString lastOpenedWidth = cfg.readEntry( "X-KDE-LastOpenedWith" ); 00852 if ( !lastOpenedWidth.isEmpty() ) 00853 run->setPreferredService( lastOpenedWidth ); 00854 00855 return -1; // we don't want to return 0, but we don't want to return a pid 00856 } 00857 00858 pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & ) 00859 { 00860 // Hmm, can't really use keditfiletype since we might be looking 00861 // at the global file, or at a file not in share/mimelnk... 00862 00863 QStringList args; 00864 args << "openProperties"; 00865 args << url.path(); 00866 00867 int pid; 00868 if ( !KApplication::kdeinitExec("kfmclient", args, 0, &pid) ) 00869 return pid; 00870 00871 KProcess p; 00872 p << "kfmclient" << args; 00873 p.start(KProcess::DontCare); 00874 return p.pid(); 00875 } 00876 00877 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url ) 00878 { 00879 QValueList<Service> result; 00880 00881 if ( !_url.isLocalFile() ) 00882 return result; 00883 00884 KSimpleConfig cfg( _url.path(), true ); 00885 cfg.setDesktopGroup(); 00886 QString type = cfg.readEntry( "Type" ); 00887 00888 if ( type.isEmpty() ) 00889 return result; 00890 00891 if ( type == "FSDevice" ) 00892 { 00893 QString dev = cfg.readEntry( "Dev" ); 00894 if ( dev.isEmpty() ) 00895 { 00896 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() ); 00897 KMessageBoxWrapper::error( 0, tmp); 00898 } 00899 else 00900 { 00901 QString mp = KIO::findDeviceMountPoint( dev ); 00902 // not mounted ? 00903 if ( mp.isEmpty() ) 00904 { 00905 Service mount; 00906 mount.m_strName = i18n("Mount"); 00907 mount.m_type = ST_MOUNT; 00908 result.append( mount ); 00909 } 00910 else 00911 { 00912 Service unmount; 00913 #ifdef HAVE_VOLMGT 00914 /* 00915 * Solaris' volume management can only umount+eject 00916 */ 00917 unmount.m_strName = i18n("Eject"); 00918 #else 00919 unmount.m_strName = i18n("Unmount"); 00920 #endif 00921 unmount.m_type = ST_UNMOUNT; 00922 result.append( unmount ); 00923 } 00924 } 00925 } 00926 00927 return result; 00928 } 00929 00930 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, bool bLocalFiles ) 00931 { 00932 QValueList<Service> result; 00933 00934 KSimpleConfig cfg( path, true ); 00935 00936 cfg.setDesktopGroup(); 00937 00938 if ( !cfg.hasKey( "Actions" ) ) 00939 return result; 00940 00941 if ( cfg.hasKey( "TryExec" ) ) 00942 { 00943 QString tryexec = cfg.readPathEntry( "TryExec" ); 00944 QString exe = KStandardDirs::findExe( tryexec ); 00945 if (exe.isEmpty()) { 00946 return result; 00947 } 00948 } 00949 00950 QStringList keys = cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator! 00951 00952 if ( keys.count() == 0 ) 00953 return result; 00954 00955 QStringList::ConstIterator it = keys.begin(); 00956 QStringList::ConstIterator end = keys.end(); 00957 for ( ; it != end; ++it ) 00958 { 00959 //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl; 00960 00961 QString group = *it; 00962 00963 if (group == "_SEPARATOR_") 00964 { 00965 Service s; 00966 result.append(s); 00967 continue; 00968 } 00969 00970 group.prepend( "Desktop Action " ); 00971 00972 bool bInvalidMenu = false; 00973 00974 if ( cfg.hasGroup( group ) ) 00975 { 00976 cfg.setGroup( group ); 00977 00978 if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) ) 00979 bInvalidMenu = true; 00980 else 00981 { 00982 QString exec = cfg.readPathEntry( "Exec" ); 00983 if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") ) 00984 { 00985 Service s; 00986 s.m_strName = cfg.readEntry( "Name" ); 00987 s.m_strIcon = cfg.readEntry( "Icon" ); 00988 s.m_strExec = exec; 00989 s.m_type = ST_USER_DEFINED; 00990 s.m_display = !cfg.readBoolEntry( "NoDisplay" ); 00991 result.append( s ); 00992 } 00993 } 00994 } 00995 else 00996 bInvalidMenu = true; 00997 00998 if ( bInvalidMenu ) 00999 { 01000 QString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it ); 01001 KMessageBoxWrapper::error( 0, tmp ); 01002 } 01003 } 01004 01005 return result; 01006 } 01007 01008 void KDEDesktopMimeType::executeService( const QString& _url, KDEDesktopMimeType::Service& _service ) 01009 { 01010 KURL u; 01011 u.setPath(_url); 01012 KURL::List lst; 01013 lst.append( u ); 01014 executeService( lst, _service ); 01015 } 01016 01017 void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service ) 01018 { 01019 //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl; 01020 01021 if ( _service.m_type == ST_USER_DEFINED ) 01022 { 01023 kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName 01024 << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl; 01025 KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon ); 01026 // The action may update the desktop file. Example: eject unmounts (#5129). 01027 KDirNotify_stub allDirNotify("*", "KDirNotify*"); 01028 allDirNotify.FilesChanged( urls ); 01029 return; 01030 } 01031 else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT ) 01032 { 01033 Q_ASSERT( urls.count() == 1 ); 01034 QString path = urls.first().path(); 01035 //kdDebug(7009) << "MOUNT&UNMOUNT" << endl; 01036 01037 KSimpleConfig cfg( path, true ); 01038 cfg.setDesktopGroup(); 01039 QString dev = cfg.readEntry( "Dev" ); 01040 if ( dev.isEmpty() ) 01041 { 01042 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path ); 01043 KMessageBoxWrapper::error( 0, tmp ); 01044 return; 01045 } 01046 QString mp = KIO::findDeviceMountPoint( dev ); 01047 01048 if ( _service.m_type == ST_MOUNT ) 01049 { 01050 // Already mounted? Strange, but who knows ... 01051 if ( !mp.isEmpty() ) 01052 { 01053 kdDebug(7009) << "ALREADY Mounted" << endl; 01054 return; 01055 } 01056 01057 bool ro = cfg.readBoolEntry( "ReadOnly", false ); 01058 QString fstype = cfg.readEntry( "FSType" ); 01059 if ( fstype == "Default" ) // KDE-1 thing 01060 fstype = QString::null; 01061 QString point = cfg.readEntry( "MountPoint" ); 01062 (void)new KAutoMount( ro, fstype, dev, point, path, false ); 01063 } 01064 else if ( _service.m_type == ST_UNMOUNT ) 01065 { 01066 // Not mounted? Strange, but who knows ... 01067 if ( mp.isEmpty() ) 01068 return; 01069 01070 (void)new KAutoUnmount( mp, path ); 01071 } 01072 } 01073 else 01074 assert( 0 ); 01075 } 01076 01077 const QString & KMimeType::defaultMimeType() 01078 { 01079 static const QString & s_strDefaultMimeType = 01080 KGlobal::staticQString( "application/octet-stream" ); 01081 return s_strDefaultMimeType; 01082 } 01083 01084 void KMimeType::virtual_hook( int id, void* data ) 01085 { KServiceType::virtual_hook( id, data ); } 01086 01087 void KFolderType::virtual_hook( int id, void* data ) 01088 { KMimeType::virtual_hook( id, data ); } 01089 01090 void KDEDesktopMimeType::virtual_hook( int id, void* data ) 01091 { KMimeType::virtual_hook( id, data ); } 01092 01093 void KExecMimeType::virtual_hook( int id, void* data ) 01094 { KMimeType::virtual_hook( id, data ); } 01095 01096 #include "kmimetyperesolver.moc" 01097
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:27 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003