• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

kmimetype.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 // $Id$
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 #include <kde_file.h>
00061 
00062 template class KSharedPtr<KMimeType>;
00063 template class QValueList<KMimeType::Ptr>;
00064 
00065 KMimeType::Ptr KMimeType::s_pDefaultType = 0L;
00066 bool KMimeType::s_bChecked = false;
00067 
00068 void KMimeType::buildDefaultType()
00069 {
00070   assert ( !s_pDefaultType );
00071   // Try to find the default type
00072   KServiceType * mime = KServiceTypeFactory::self()->
00073         findServiceTypeByName( defaultMimeType() );
00074 
00075   if (mime && mime->isType( KST_KMimeType ))
00076   {
00077       s_pDefaultType = KMimeType::Ptr((KMimeType *) mime);
00078   }
00079   else
00080   {
00081      errorMissingMimeType( defaultMimeType() );
00082      KStandardDirs stdDirs;
00083      QString sDefaultMimeType = stdDirs.resourceDirs("mime").first()+defaultMimeType()+".desktop";
00084      s_pDefaultType = new KMimeType( sDefaultMimeType, defaultMimeType(),
00085                                      "unknown", "mime", QStringList() );
00086   }
00087 }
00088 
00089 KMimeType::Ptr KMimeType::defaultMimeTypePtr()
00090 {
00091   if ( !s_pDefaultType ) // we need a default type first
00092     buildDefaultType();
00093   return s_pDefaultType;
00094 }
00095 
00096 // Check for essential mimetypes
00097 void KMimeType::checkEssentialMimeTypes()
00098 {
00099   if ( s_bChecked ) // already done
00100     return;
00101   if ( !s_pDefaultType ) // we need a default type first
00102     buildDefaultType();
00103 
00104   s_bChecked = true; // must be done before building mimetypes
00105 
00106   // No Mime-Types installed ?
00107   // Lets do some rescue here.
00108   if ( !KServiceTypeFactory::self()->checkMimeTypes() )
00109   {
00110     KMessageBoxWrapper::error( 0L, i18n( "No mime types installed." ) );
00111     return; // no point in going any further
00112   }
00113 
00114   if ( KMimeType::mimeType( "inode/directory" ) == s_pDefaultType )
00115     errorMissingMimeType( "inode/directory" );
00116   if ( KMimeType::mimeType( "inode/directory-locked" ) == s_pDefaultType )
00117     errorMissingMimeType( "inode/directory-locked" );
00118   if ( KMimeType::mimeType( "inode/blockdevice" ) == s_pDefaultType )
00119     errorMissingMimeType( "inode/blockdevice" );
00120   if ( KMimeType::mimeType( "inode/chardevice" ) == s_pDefaultType )
00121     errorMissingMimeType( "inode/chardevice" );
00122   if ( KMimeType::mimeType( "inode/socket" ) == s_pDefaultType )
00123     errorMissingMimeType( "inode/socket" );
00124   if ( KMimeType::mimeType( "inode/fifo" ) == s_pDefaultType )
00125     errorMissingMimeType( "inode/fifo" );
00126   if ( KMimeType::mimeType( "application/x-shellscript" ) == s_pDefaultType )
00127     errorMissingMimeType( "application/x-shellscript" );
00128   if ( KMimeType::mimeType( "application/x-executable" ) == s_pDefaultType )
00129     errorMissingMimeType( "application/x-executable" );
00130   if ( KMimeType::mimeType( "application/x-desktop" ) == s_pDefaultType )
00131     errorMissingMimeType( "application/x-desktop" );
00132 }
00133 
00134 void KMimeType::errorMissingMimeType( const QString& _type )
00135 {
00136   QString tmp = i18n( "Could not find mime type\n%1" ).arg( _type );
00137 
00138   KMessageBoxWrapper::sorry( 0, tmp );
00139 }
00140 
00141 KMimeType::Ptr KMimeType::mimeType( const QString& _name )
00142 {
00143   KServiceType * mime = KServiceTypeFactory::self()->findServiceTypeByName( _name );
00144 
00145   if ( !mime || !mime->isType( KST_KMimeType ) )
00146   {
00147     // When building ksycoca, findServiceTypeByName doesn't create an object
00148     // but returns one from a dict.
00149     if ( !KSycoca::self()->isBuilding() )
00150         delete mime;
00151     if ( !s_pDefaultType )
00152       buildDefaultType();
00153     return s_pDefaultType;
00154   }
00155 
00156   // We got a mimetype
00157   return KMimeType::Ptr((KMimeType *) mime);
00158 }
00159 
00160 KMimeType::List KMimeType::allMimeTypes()
00161 {
00162   return KServiceTypeFactory::self()->allMimeTypes();
00163 }
00164 
00165 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
00166                                      bool _is_local_file, bool _fast_mode )
00167 {
00168   checkEssentialMimeTypes();
00169   QString path = _url.path();
00170 
00171   if ( !_fast_mode && !_is_local_file && _url.isLocalFile() )
00172     _is_local_file = true;
00173 
00174   if ( !_fast_mode && _is_local_file && (_mode == 0 || _mode == (mode_t)-1) )
00175   {
00176     KDE_struct_stat buff;
00177     if ( KDE_stat( QFile::encodeName(path), &buff ) != -1 )
00178       _mode = buff.st_mode;
00179   }
00180 
00181   // Look at mode_t first
00182   if ( S_ISDIR( _mode ) )
00183   {
00184     // Special hack for local files. We want to see whether we
00185     // are allowed to enter the directory
00186     if ( _is_local_file )
00187     {
00188       if ( access( QFile::encodeName(path), R_OK ) == -1 )
00189         return mimeType( "inode/directory-locked" );
00190     }
00191     return mimeType( "inode/directory" );
00192   }
00193   if ( S_ISCHR( _mode ) )
00194     return mimeType( "inode/chardevice" );
00195   if ( S_ISBLK( _mode ) )
00196     return mimeType( "inode/blockdevice" );
00197   if ( S_ISFIFO( _mode ) )
00198     return mimeType( "inode/fifo" );
00199   if ( S_ISSOCK( _mode ) )
00200     return mimeType( "inode/socket" );
00201   // KMimeMagic can do that better for local files
00202   if ( !_is_local_file && S_ISREG( _mode ) && ( _mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
00203     return mimeType( "application/x-executable" );
00204 
00205   QString fileName ( _url.fileName() );
00206 
00207   static const QString& slash = KGlobal::staticQString("/");
00208   if ( ! fileName.isNull() && !path.endsWith( slash ) )
00209   {
00210       // Try to find it out by looking at the filename
00211       KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName );
00212       if ( mime )
00213       {
00214         // Found something - can we trust it ? (e.g. don't trust *.pl over HTTP, could be anything)
00215         if ( _is_local_file || _url.hasSubURL() || // Explicitly trust suburls
00216              KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) )
00217         {
00218             if ( _is_local_file && !_fast_mode ) {
00219                 if ( mime->patternsAccuracy()<100 )
00220                 {
00221                     KMimeMagicResult* result =
00222                             KMimeMagic::self()->findFileType( path );
00223 
00224                     if ( result && result->isValid() && result->accuracy() > 0 )
00225                         return mimeType( result->mimeType() );
00226                 }
00227             }
00228 
00229             return mime;
00230         }
00231       }
00232 
00233       static const QString& dotdesktop = KGlobal::staticQString(".desktop");
00234       static const QString& dotkdelnk = KGlobal::staticQString(".kdelnk");
00235       static const QString& dotdirectory = KGlobal::staticQString(".directory");
00236 
00237       // Another filename binding, hardcoded, is .desktop:
00238       if ( fileName.endsWith( dotdesktop ) )
00239         return mimeType( "application/x-desktop" );
00240       // Another filename binding, hardcoded, is .kdelnk;
00241       // this is preserved for backwards compatibility
00242       if ( fileName.endsWith( dotkdelnk ) )
00243         return mimeType( "application/x-desktop" );
00244       // .directory files are detected as x-desktop by mimemagic
00245       // but don't have a Type= entry. Better cheat and say they are text files
00246       if ( fileName == dotdirectory )
00247         return mimeType( "text/plain" );
00248     }
00249 
00250   if ( !_is_local_file || _fast_mode )
00251   {
00252     QString def = KProtocolInfo::defaultMimetype( _url );
00253     if ( !def.isEmpty() && def != defaultMimeType() )
00254     {
00255        // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
00256        return mimeType( def );
00257     }
00258     if ( path.endsWith( slash ) || path.isEmpty() )
00259     {
00260       // We have no filename at all. Maybe the protocol has a setting for
00261       // which mimetype this means (e.g. directory).
00262       // For HTTP (def==defaultMimeType()) we don't assume anything,
00263       // because of redirections (e.g. freshmeat downloads).
00264       if ( def.isEmpty() )
00265       {
00266           // Assume inode/directory, if the protocol supports listing.
00267           if ( KProtocolInfo::supportsListing( _url ) )
00268               return mimeType( QString::fromLatin1("inode/directory") );
00269           else
00270               return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
00271       }
00272     }
00273 
00274     // No more chances for non local URLs
00275     return defaultMimeTypePtr();
00276   }
00277 
00278   // Do some magic for local files
00279   //kdDebug(7009) << QString("Mime Type finding for '%1'").arg(path) << endl;
00280   KMimeMagicResult* result = KMimeMagic::self()->findFileType( path );
00281 
00282   // If we still did not find it, we must assume the default mime type
00283   if ( !result || !result->isValid() )
00284     return defaultMimeTypePtr();
00285 
00286   // The mimemagic stuff was successful
00287   return mimeType( result->mimeType() );
00288 }
00289 
00290 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
00291                                      bool _is_local_file, bool _fast_mode,
00292                                      bool *accurate)
00293 {
00294     KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode);
00295     if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr());
00296     return mime;
00297 }
00298 
00299 KMimeType::Ptr KMimeType::diagnoseFileName(const QString &fileName, QString &pattern)
00300 {
00301   return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern );
00302 }
00303 
00304 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode, bool fast_mode )
00305 {
00306     KURL u;
00307     u.setPath(path);
00308     return findByURL( u, mode, true, fast_mode );
00309 }
00310 
00311 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy )
00312 {
00313   KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data);
00314   if (accuracy)
00315       *accuracy = result->accuracy();
00316   return mimeType( result->mimeType() );
00317 }
00318 
00319 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy )
00320 {
00321   KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName);
00322   if (accuracy)
00323       *accuracy = result->accuracy();
00324   return mimeType( result->mimeType() );
00325 }
00326 
00327 #define GZIP_MAGIC1 0x1f
00328 #define GZIP_MAGIC2 0x8b
00329 
00330 KMimeType::Format KMimeType::findFormatByFileContent( const QString &fileName )
00331 {
00332   KMimeType::Format result;
00333   result.compression = Format::NoCompression;
00334   KMimeType::Ptr mime = findByPath(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     QString inherits = config->readEntry( XKDEIsAlso );
00396     if ( inherits != name() )
00397         m_mapProps.insert( XKDEIsAlso, inherits );
00398     else
00399         kdWarning(7009) << "Error: " << inherits << " inherits from itself!!!!" << endl;
00400   }
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     const KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(),
00506                                          false /*HACK*/);
00507     static const QString& unknown = KGlobal::staticQString("unknown");
00508     const QString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() );
00509     QString i = mimeTypeIcon;
00510 
00511     // if we don't find an icon, maybe we can use the one for the protocol
00512     if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr()
00513         // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
00514         || _url.path().length() <= 1 )
00515     {
00516         i = favIconForURL( _url ); // maybe there is a favicon?
00517 
00518         if ( i.isEmpty() )
00519             i = KProtocolInfo::icon( _url.protocol() );
00520 
00521         // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
00522         if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
00523             i = mimeTypeIcon;
00524     }
00525     return i;
00526 }
00527 
00528 QString KMimeType::favIconForURL( const KURL& url )
00529 {
00530     // this method will be called quite often, so better not read the config
00531     // again and again.
00532     static bool useFavIcons = true;
00533     static bool check = true;
00534     if ( check ) {
00535         check = false;
00536         KConfig *config = KGlobal::config();
00537         KConfigGroupSaver cs( config, "HTML Settings" );
00538         useFavIcons = config->readBoolEntry( "EnableFavicon", true );
00539     }
00540 
00541     if ( url.isLocalFile() || !url.protocol().startsWith("http")
00542          || !useFavIcons )
00543         return QString::null;
00544 
00545     DCOPRef kded( "kded", "favicons" );
00546     DCOPReply result = kded.call( "iconForURL(KURL)", url );
00547     if ( result.isValid() )
00548         return result;
00549 
00550     return QString::null;
00551 }
00552 
00553 QString KMimeType::parentMimeType() const
00554 {
00555   QVariant v = property("X-KDE-IsAlso");
00556   return v.toString();
00557 }
00558 
00559 bool KMimeType::is( const QString& mimeTypeName ) const
00560 {
00561   if ( name() == mimeTypeName )
00562       return true;
00563   QString st = parentMimeType();
00564   //if (st.isEmpty()) kdDebug(7009)<<"Parent mimetype is empty"<<endl;
00565   while ( !st.isEmpty() )
00566   {
00567       //kdDebug(7009)<<"Checking parent mime type: "<<st<<endl;
00568       KMimeType::Ptr ptr = KMimeType::mimeType( st );
00569       if (!ptr) return false; //error
00570       if ( ptr->name() == mimeTypeName )
00571           return true;
00572       st = ptr->parentMimeType();
00573   }
00574   return false;
00575 }
00576 
00577 int KMimeType::patternsAccuracy() const {
00578   QVariant v = property("X-KDE-PatternsAccuracy");
00579   if (!v.isValid()) return 100;
00580   else
00581       return v.toInt();
00582 }
00583 
00584 
00585 /*******************************************************
00586  *
00587  * KFolderType
00588  *
00589  ******************************************************/
00590 
00591 QString KFolderType::icon( const QString& _url, bool _is_local ) const
00592 {
00593   if ( !_is_local || _url.isEmpty() )
00594     return KMimeType::icon( _url, _is_local );
00595 
00596   return KFolderType::icon( KURL(_url), _is_local );
00597 }
00598 
00599 QString KFolderType::icon( const KURL& _url, bool _is_local ) const
00600 {
00601   if ( !_is_local )
00602     return KMimeType::icon( _url, _is_local );
00603 
00604   KURL u( _url );
00605   u.addPath( ".directory" );
00606 
00607   QString icon;
00608   // using KStandardDirs as this one checks for path being
00609   // a file instead of a directory
00610   if ( KStandardDirs::exists( u.path() ) )
00611   {
00612     KSimpleConfig cfg( u.path(), true );
00613     cfg.setDesktopGroup();
00614     icon = cfg.readEntry( "Icon" );
00615     QString empty_icon = cfg.readEntry( "EmptyIcon" );
00616 
00617     if ( !empty_icon.isEmpty() )
00618     {
00619       bool isempty = false;
00620       DIR *dp = 0L;
00621       struct dirent *ep;
00622       dp = opendir( QFile::encodeName(_url.path()) );
00623       if ( dp )
00624       {
00625         QValueList<QCString> entries;
00626         // Note that readdir isn't guaranteed to return "." and ".." first (#79826)
00627         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00628         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00629         if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory
00630           isempty = true;
00631         else {
00632           entries.append( ep->d_name );
00633           if ( readdir( dp ) == 0 ) { // only three
00634             // check if we got "." ".." and ".directory"
00635             isempty = entries.find( "." ) != entries.end() &&
00636                       entries.find( ".." ) != entries.end() &&
00637                       entries.find( ".directory" ) != entries.end();
00638           }
00639         }
00640         if (!isempty && !strcmp(ep->d_name, ".directory"))
00641           isempty = (readdir(dp) == 0L);
00642         closedir( dp );
00643       }
00644 
00645       if ( isempty )
00646         return empty_icon;
00647     }
00648   }
00649 
00650   if ( icon.isEmpty() )
00651     return KMimeType::icon( _url, _is_local );
00652 
00653   if ( icon.startsWith( "./" ) ) {
00654     // path is relative with respect to the location
00655     // of the .directory file (#73463)
00656     KURL v( _url );
00657     v.addPath( icon.mid( 2 ) );
00658     icon = v.path();
00659   }
00660 
00661   return icon;
00662 }
00663 
00664 QString KFolderType::comment( const QString& _url, bool _is_local ) const
00665 {
00666   if ( !_is_local || _url.isEmpty() )
00667     return KMimeType::comment( _url, _is_local );
00668 
00669   return KFolderType::comment( KURL(_url), _is_local );
00670 }
00671 
00672 QString KFolderType::comment( const KURL& _url, bool _is_local ) const
00673 {
00674   if ( !_is_local )
00675     return KMimeType::comment( _url, _is_local );
00676 
00677   KURL u( _url );
00678   u.addPath( ".directory" );
00679 
00680   KSimpleConfig cfg( u.path(), true );
00681   cfg.setDesktopGroup();
00682   QString comment = cfg.readEntry( "Comment" );
00683   if ( comment.isEmpty() )
00684     return KMimeType::comment( _url, _is_local );
00685 
00686   return comment;
00687 }
00688 
00689 /*******************************************************
00690  *
00691  * KDEDesktopMimeType
00692  *
00693  ******************************************************/
00694 
00695 QString KDEDesktopMimeType::icon( const QString& _url, bool _is_local ) const
00696 {
00697   if ( !_is_local || _url.isEmpty() )
00698     return KMimeType::icon( _url, _is_local );
00699 
00700   KURL u( _url );
00701   return icon( u, _is_local );
00702 }
00703 
00704 QString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const
00705 {
00706   if ( !_is_local )
00707     return KMimeType::icon( _url, _is_local );
00708 
00709   KSimpleConfig cfg( _url.path(), true );
00710   cfg.setDesktopGroup();
00711   QString icon = cfg.readEntry( "Icon" );
00712   QString type = cfg.readEntry( "Type" );
00713 
00714   if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for
00715                                               // backwards compatibility
00716   {
00717     QString unmount_icon = cfg.readEntry( "UnmountIcon" );
00718     QString dev = cfg.readEntry( "Dev" );
00719     if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
00720     {
00721       QString mp = KIO::findDeviceMountPoint( dev );
00722       // Is the device not mounted ?
00723       if ( mp.isNull() )
00724         return unmount_icon;
00725     }
00726   } else if ( type == "Link" ) {
00727       const QString emptyIcon = cfg.readEntry( "EmptyIcon" );
00728       if ( !emptyIcon.isEmpty() ) {
00729           const QString u = cfg.readPathEntry( "URL" );
00730           const KURL url( u );
00731           if ( url.protocol() == "trash" ) {
00732               // We need to find if the trash is empty, preferrably without using a KIO job.
00733               // So instead kio_trash leaves an entry in its config file for us.
00734               KSimpleConfig trashConfig( "trashrc", true );
00735               trashConfig.setGroup( "Status" );
00736               if ( trashConfig.readBoolEntry( "Empty", true ) ) {
00737                   return emptyIcon;
00738               }
00739           }
00740       }
00741   }
00742 
00743   if ( icon.isEmpty() )
00744     return KMimeType::icon( _url, _is_local );
00745 
00746   return icon;
00747 }
00748 
00749 QPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
00750                                     int _state, QString * _path ) const
00751 {
00752   QString _icon = icon( _url, _url.isLocalFile() );
00753   QPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group,
00754         _force_size, _state, _path, false );
00755   if ( pix.isNull() )
00756       pix = KGlobal::iconLoader()->loadIcon( "unknown", _group,
00757         _force_size, _state, _path, false );
00758   return pix;
00759 }
00760 
00761 QString KDEDesktopMimeType::comment( const QString& _url, bool _is_local ) const
00762 {
00763   if ( !_is_local || _url.isEmpty() )
00764     return KMimeType::comment( _url, _is_local );
00765 
00766   KURL u( _url );
00767   return comment( u, _is_local );
00768 }
00769 
00770 QString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const
00771 {
00772   if ( !_is_local )
00773     return KMimeType::comment( _url, _is_local );
00774 
00775   KSimpleConfig cfg( _url.path(), true );
00776   cfg.setDesktopGroup();
00777   QString comment = cfg.readEntry( "Comment" );
00778   if ( comment.isEmpty() )
00779     return KMimeType::comment( _url, _is_local );
00780 
00781   return comment;
00782 }
00783 
00784 pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local )
00785 {
00786   // It might be a security problem to run external untrusted desktop
00787   // entry files
00788   if ( !_is_local )
00789     return 0;
00790 
00791   KSimpleConfig cfg( u.path(), true );
00792   cfg.setDesktopGroup();
00793   QString type = cfg.readEntry( "Type" );
00794   if ( type.isEmpty() )
00795   {
00796     QString tmp = i18n("The desktop entry file %1 "
00797                        "has no Type=... entry.").arg(u.path() );
00798     KMessageBoxWrapper::error( 0, tmp);
00799     return 0;
00800   }
00801 
00802   //kdDebug(7009) << "TYPE = " << type.data() << endl;
00803 
00804   if ( type == "FSDevice" )
00805     return runFSDevice( u, cfg );
00806   else if ( type == "Application" )
00807     return runApplication( u, u.path() );
00808   else if ( type == "Link" )
00809   {
00810     cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon)
00811     return runLink( u, cfg );
00812   }
00813   else if ( type == "MimeType" )
00814     return runMimeType( u, cfg );
00815 
00816 
00817   QString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type );
00818   KMessageBoxWrapper::error( 0, tmp);
00819 
00820   return 0;
00821 }
00822 
00823 pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg )
00824 {
00825   pid_t retval = 0;
00826 
00827   QString dev = cfg.readEntry( "Dev" );
00828 
00829   if ( dev.isEmpty() )
00830   {
00831     QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00832     KMessageBoxWrapper::error( 0, tmp);
00833     return retval;
00834   }
00835 
00836   QString mp = KIO::findDeviceMountPoint( dev );
00837   // Is the device already mounted ?
00838   if ( !mp.isNull() )
00839   {
00840     KURL mpURL;
00841     mpURL.setPath( mp );
00842     // Open a new window
00843     retval = KRun::runURL( mpURL, QString::fromLatin1("inode/directory") );
00844   }
00845   else
00846   {
00847     bool ro = cfg.readBoolEntry( "ReadOnly", false );
00848     QString fstype = cfg.readEntry( "FSType" );
00849     if ( fstype == "Default" ) // KDE-1 thing
00850       fstype = QString::null;
00851     QString point = cfg.readEntry( "MountPoint" );
00852 #ifndef Q_WS_WIN
00853     (void) new KAutoMount( ro, fstype, dev, point, _url.path() );
00854 #endif
00855     retval = -1; // we don't want to return 0, but we don't want to return a pid
00856   }
00857 
00858   return retval;
00859 }
00860 
00861 pid_t KDEDesktopMimeType::runApplication( const KURL& , const QString & _serviceFile )
00862 {
00863   KService s( _serviceFile );
00864   if ( !s.isValid() )
00865     // The error message was already displayed, so we can just quit here
00866     return 0;
00867 
00868   KURL::List lst;
00869   return KRun::run( s, lst );
00870 }
00871 
00872 pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg )
00873 {
00874   QString u = cfg.readPathEntry( "URL" );
00875   if ( u.isEmpty() )
00876   {
00877     QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
00878     KMessageBoxWrapper::error( 0, tmp );
00879     return 0;
00880   }
00881 
00882   KURL url ( u );
00883   KRun* run = new KRun(url);
00884 
00885   // X-KDE-LastOpenedWith holds the service desktop entry name that
00886   // was should be preferred for opening this URL if possible.
00887   // This is used by the Recent Documents menu for instance.
00888   QString lastOpenedWidth = cfg.readEntry( "X-KDE-LastOpenedWith" );
00889   if ( !lastOpenedWidth.isEmpty() )
00890       run->setPreferredService( lastOpenedWidth );
00891 
00892   return -1; // we don't want to return 0, but we don't want to return a pid
00893 }
00894 
00895 pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & )
00896 {
00897   // Hmm, can't really use keditfiletype since we might be looking
00898   // at the global file, or at a file not in share/mimelnk...
00899 
00900   QStringList args;
00901   args << "openProperties";
00902   args << url.path();
00903 
00904   int pid;
00905   if ( !KApplication::kdeinitExec("kfmclient", args, 0, &pid) )
00906       return pid;
00907 
00908   KProcess p;
00909   p << "kfmclient" << args;
00910   p.start(KProcess::DontCare);
00911   return p.pid();
00912 }
00913 
00914 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url )
00915 {
00916   QValueList<Service> result;
00917 
00918   if ( !_url.isLocalFile() )
00919     return result;
00920 
00921   KSimpleConfig cfg( _url.path(), true );
00922   cfg.setDesktopGroup();
00923   QString type = cfg.readEntry( "Type" );
00924 
00925   if ( type.isEmpty() )
00926     return result;
00927 
00928   if ( type == "FSDevice" )
00929   {
00930     QString dev = cfg.readEntry( "Dev" );
00931     if ( dev.isEmpty() )
00932     {
00933       QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00934       KMessageBoxWrapper::error( 0, tmp);
00935     }
00936     else
00937     {
00938       QString mp = KIO::findDeviceMountPoint( dev );
00939       // not mounted ?
00940       if ( mp.isEmpty() )
00941       {
00942         Service mount;
00943         mount.m_strName = i18n("Mount");
00944         mount.m_type = ST_MOUNT;
00945         result.append( mount );
00946       }
00947       else
00948       {
00949         Service unmount;
00950 #ifdef HAVE_VOLMGT
00951         /*
00952          *  Solaris' volume management can only umount+eject
00953          */
00954         unmount.m_strName = i18n("Eject");
00955 #else
00956         unmount.m_strName = i18n("Unmount");
00957 #endif
00958         unmount.m_type = ST_UNMOUNT;
00959         result.append( unmount );
00960       }
00961     }
00962   }
00963 
00964   return result;
00965 }
00966 
00967 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, bool bLocalFiles )
00968 {
00969   KSimpleConfig cfg( path, true );
00970   return userDefinedServices( path, cfg, bLocalFiles );
00971 }
00972 
00973 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, KConfig& cfg, bool bLocalFiles )
00974 {
00975  return userDefinedServices( path, cfg, bLocalFiles, KURL::List() );
00976 }
00977 
00978 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, KConfig& cfg, bool bLocalFiles, const KURL::List & file_list )
00979 {
00980   QValueList<Service> result;
00981 
00982   cfg.setDesktopGroup();
00983 
00984   if ( !cfg.hasKey( "Actions" ) && !cfg.hasKey( "X-KDE-GetActionMenu") )
00985     return result;
00986 
00987   if ( cfg.hasKey( "TryExec" ) )
00988   {
00989       QString tryexec = cfg.readPathEntry( "TryExec" );
00990       QString exe =  KStandardDirs::findExe( tryexec );
00991       if (exe.isEmpty()) {
00992           return result;
00993       }
00994   }
00995 
00996   QStringList keys;
00997 
00998   if( cfg.hasKey( "X-KDE-GetActionMenu" )) {
00999     QString dcopcall = cfg.readEntry( "X-KDE-GetActionMenu" );
01000     const QCString app = dcopcall.section(' ', 0,0).utf8();
01001 
01002     QByteArray dataToSend;
01003     QDataStream dataStream(dataToSend, IO_WriteOnly);
01004     dataStream << file_list;
01005     QCString replyType;
01006     QByteArray replyData;
01007     QCString object =    dcopcall.section(' ', 1,-2).utf8();
01008     QString function =  dcopcall.section(' ', -1);
01009     if(!function.endsWith("(KURL::List)")) {
01010       kdWarning() << "Desktop file " << path << " contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
01011     } else {
01012       if(kapp->dcopClient()->call( app, object,
01013                    function.utf8(),
01014                    dataToSend, replyType, replyData, true, -1)
01015         && replyType == "QStringList" ) {
01016 
01017         QDataStream dataStreamIn(replyData, IO_ReadOnly);
01018         dataStreamIn >> keys;
01019       }
01020     }
01021   }
01022 
01023   keys += cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator!
01024 
01025   if ( keys.count() == 0 )
01026     return result;
01027 
01028   QStringList::ConstIterator it = keys.begin();
01029   QStringList::ConstIterator end = keys.end();
01030   for ( ; it != end; ++it )
01031   {
01032     //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl;
01033 
01034     QString group = *it;
01035 
01036     if (group == "_SEPARATOR_")
01037     {
01038         Service s;
01039         result.append(s);
01040         continue;
01041     }
01042 
01043     group.prepend( "Desktop Action " );
01044 
01045     bool bInvalidMenu = false;
01046 
01047     if ( cfg.hasGroup( group ) )
01048     {
01049       cfg.setGroup( group );
01050 
01051       if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) )
01052         bInvalidMenu = true;
01053       else
01054       {
01055         QString exec = cfg.readPathEntry( "Exec" );
01056         if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") )
01057         {
01058           Service s;
01059           s.m_strName = cfg.readEntry( "Name" );
01060           s.m_strIcon = cfg.readEntry( "Icon" );
01061           s.m_strExec = exec;
01062           s.m_type = ST_USER_DEFINED;
01063           s.m_display = !cfg.readBoolEntry( "NoDisplay" );
01064           result.append( s );
01065         }
01066       }
01067     }
01068     else
01069       bInvalidMenu = true;
01070 
01071     if ( bInvalidMenu )
01072     {
01073       QString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
01074       KMessageBoxWrapper::error( 0, tmp );
01075     }
01076   }
01077 
01078   return result;
01079 }
01080 
01081 void KDEDesktopMimeType::executeService( const QString& _url, KDEDesktopMimeType::Service& _service )
01082 {
01083     KURL u;
01084     u.setPath(_url);
01085     KURL::List lst;
01086     lst.append( u );
01087     executeService( lst, _service );
01088 }
01089 
01090 void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service )
01091 {
01092   //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl;
01093 
01094   if ( _service.m_type == ST_USER_DEFINED )
01095   {
01096     kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName
01097               << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl;
01098     KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
01099     // The action may update the desktop file. Example: eject unmounts (#5129).
01100     KDirNotify_stub allDirNotify("*", "KDirNotify*");
01101     allDirNotify.FilesChanged( urls );
01102     return;
01103   }
01104   else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
01105   {
01106     Q_ASSERT( urls.count() == 1 );
01107     QString path = urls.first().path();
01108     //kdDebug(7009) << "MOUNT&UNMOUNT" << endl;
01109 
01110     KSimpleConfig cfg( path, true );
01111     cfg.setDesktopGroup();
01112     QString dev = cfg.readEntry( "Dev" );
01113     if ( dev.isEmpty() )
01114     {
01115       QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
01116       KMessageBoxWrapper::error( 0, tmp );
01117       return;
01118     }
01119     QString mp = KIO::findDeviceMountPoint( dev );
01120 
01121     if ( _service.m_type == ST_MOUNT )
01122     {
01123       // Already mounted? Strange, but who knows ...
01124       if ( !mp.isEmpty() )
01125       {
01126         kdDebug(7009) << "ALREADY Mounted" << endl;
01127         return;
01128       }
01129 
01130       bool ro = cfg.readBoolEntry( "ReadOnly", false );
01131       QString fstype = cfg.readEntry( "FSType" );
01132       if ( fstype == "Default" ) // KDE-1 thing
01133           fstype = QString::null;
01134       QString point = cfg.readEntry( "MountPoint" );
01135 #ifndef Q_WS_WIN
01136       (void)new KAutoMount( ro, fstype, dev, point, path, false );
01137 #endif
01138     }
01139     else if ( _service.m_type == ST_UNMOUNT )
01140     {
01141       // Not mounted? Strange, but who knows ...
01142       if ( mp.isEmpty() )
01143         return;
01144 
01145 #ifndef Q_WS_WIN
01146       (void)new KAutoUnmount( mp, path );
01147 #endif
01148     }
01149   }
01150   else
01151     assert( 0 );
01152 }
01153 
01154 const QString & KMimeType::defaultMimeType()
01155 {
01156     static const QString & s_strDefaultMimeType =
01157         KGlobal::staticQString( "application/octet-stream" );
01158     return s_strDefaultMimeType;
01159 }
01160 
01161 void KMimeType::virtual_hook( int id, void* data )
01162 { KServiceType::virtual_hook( id, data ); }
01163 
01164 void KFolderType::virtual_hook( int id, void* data )
01165 { KMimeType::virtual_hook( id, data ); }
01166 
01167 void KDEDesktopMimeType::virtual_hook( int id, void* data )
01168 { KMimeType::virtual_hook( id, data ); }
01169 
01170 void KExecMimeType::virtual_hook( int id, void* data )
01171 { KMimeType::virtual_hook( id, data ); }
01172 
01173 #include "kmimetyperesolver.moc"
01174 

kio

Skip menu "kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal