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.2.1 2004/10/18 22:27:08 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         QValueList<QCString> entries;
00616         // Note that readdir isn't guaranteed to return "." and ".." first (#79826)
00617         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00618         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00619         if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory
00620           isempty = true;
00621         else {
00622           entries.append( ep->d_name );
00623           if ( readdir( dp ) == 0 ) { // only three
00624             // check if we got "." ".." and ".directory"
00625             isempty = entries.find( "." ) != entries.end() &&
00626                       entries.find( ".." ) != entries.end() &&
00627                       entries.find( ".directory" ) != entries.end();
00628           }
00629         }
00630         if (!isempty && !strcmp(ep->d_name, ".directory"))
00631           isempty = (readdir(dp) == 0L);
00632         closedir( dp );
00633       }
00634 
00635       if ( isempty )
00636         return empty_icon;
00637     }
00638   }
00639 
00640   if ( icon.isEmpty() )
00641     return KMimeType::icon( _url, _is_local );
00642 
00643   if ( icon.startsWith( "./" ) ) {
00644     // path is relative with respect to the location
00645     // of the .directory file (#73463)
00646     KURL v( _url );
00647     v.addPath( icon.mid( 2 ) );
00648     icon = v.path();
00649   }
00650 
00651   return icon;
00652 }
00653 
00654 QString KFolderType::comment( const QString& _url, bool _is_local ) const
00655 {
00656   if ( !_is_local || _url.isEmpty() )
00657     return KMimeType::comment( _url, _is_local );
00658 
00659   return KFolderType::comment( KURL(_url), _is_local );
00660 }
00661 
00662 QString KFolderType::comment( const KURL& _url, bool _is_local ) const
00663 {
00664   if ( !_is_local )
00665     return KMimeType::comment( _url, _is_local );
00666 
00667   KURL u( _url );
00668   u.addPath( ".directory" );
00669 
00670   KSimpleConfig cfg( u.path(), true );
00671   cfg.setDesktopGroup();
00672   QString comment = cfg.readEntry( "Comment" );
00673   if ( comment.isEmpty() )
00674     return KMimeType::comment( _url, _is_local );
00675 
00676   return comment;
00677 }
00678 
00679 /*******************************************************
00680  *
00681  * KDEDesktopMimeType
00682  *
00683  ******************************************************/
00684 
00685 QString KDEDesktopMimeType::icon( const QString& _url, bool _is_local ) const
00686 {
00687   if ( !_is_local || _url.isEmpty() )
00688     return KMimeType::icon( _url, _is_local );
00689 
00690   KURL u( _url );
00691   return icon( u, _is_local );
00692 }
00693 
00694 QString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const
00695 {
00696   if ( !_is_local )
00697     return KMimeType::icon( _url, _is_local );
00698 
00699   KSimpleConfig cfg( _url.path(), true );
00700   cfg.setDesktopGroup();
00701   QString icon = cfg.readEntry( "Icon" );
00702   QString type = cfg.readEntry( "Type" );
00703 
00704   if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for
00705                                               // backwards compatibility
00706   {
00707     QString unmount_icon = cfg.readEntry( "UnmountIcon" );
00708     QString dev = cfg.readEntry( "Dev" );
00709     if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
00710     {
00711       QString mp = KIO::findDeviceMountPoint( dev );
00712       // Is the device not mounted ?
00713       if ( mp.isNull() )
00714         return unmount_icon;
00715     }
00716   }
00717 
00718   if ( icon.isEmpty() )
00719     return KMimeType::icon( _url, _is_local );
00720 
00721   return icon;
00722 }
00723 
00724 QPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
00725                                 int _state, QString * _path ) const
00726 {
00727   QString _icon = icon( _url, _url.isLocalFile() );
00728   QPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group,
00729     _force_size, _state, _path, false );
00730   if ( pix.isNull() )
00731       pix = KGlobal::iconLoader()->loadIcon( "unknown", _group,
00732     _force_size, _state, _path, false );
00733   return pix;
00734 }
00735 
00736 QString KDEDesktopMimeType::comment( const QString& _url, bool _is_local ) const
00737 {
00738   if ( !_is_local || _url.isEmpty() )
00739     return KMimeType::comment( _url, _is_local );
00740 
00741   KURL u( _url );
00742   return comment( u, _is_local );
00743 }
00744 
00745 QString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const
00746 {
00747   if ( !_is_local )
00748     return KMimeType::comment( _url, _is_local );
00749 
00750   KSimpleConfig cfg( _url.path(), true );
00751   cfg.setDesktopGroup();
00752   QString comment = cfg.readEntry( "Comment" );
00753   if ( comment.isEmpty() )
00754     return KMimeType::comment( _url, _is_local );
00755 
00756   return comment;
00757 }
00758 
00759 pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local )
00760 {
00761   // It might be a security problem to run external untrusted desktop
00762   // entry files
00763   if ( !_is_local )
00764     return 0;
00765 
00766   KSimpleConfig cfg( u.path(), true );
00767   cfg.setDesktopGroup();
00768   QString type = cfg.readEntry( "Type" );
00769   if ( type.isEmpty() )
00770   {
00771     QString tmp = i18n("The desktop entry file %1 "
00772                "has no Type=... entry.").arg(u.path() );
00773     KMessageBoxWrapper::error( 0, tmp);
00774     return 0;
00775   }
00776 
00777   //kdDebug(7009) << "TYPE = " << type.data() << endl;
00778 
00779   if ( type == "FSDevice" )
00780     return runFSDevice( u, cfg );
00781   else if ( type == "Application" )
00782     return runApplication( u, u.path() );
00783   else if ( type == "Link" )
00784   {
00785     cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon)
00786     return runLink( u, cfg );
00787   }
00788   else if ( type == "MimeType" )
00789     return runMimeType( u, cfg );
00790 
00791 
00792   QString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type );
00793   KMessageBoxWrapper::error( 0, tmp);
00794 
00795   return 0;
00796 }
00797 
00798 pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg )
00799 {
00800   pid_t retval = 0;
00801 
00802   QString dev = cfg.readEntry( "Dev" );
00803 
00804   if ( dev.isEmpty() )
00805   {
00806     QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00807     KMessageBoxWrapper::error( 0, tmp);
00808     return retval;
00809   }
00810 
00811   QString mp = KIO::findDeviceMountPoint( dev );
00812   // Is the device already mounted ?
00813   if ( !mp.isNull() )
00814   {
00815     KURL mpURL;
00816     mpURL.setPath( mp );
00817     // Open a new window
00818     retval = KRun::runURL( mpURL, QString::fromLatin1("inode/directory") );
00819   }
00820   else
00821   {
00822     bool ro = cfg.readBoolEntry( "ReadOnly", false );
00823     QString fstype = cfg.readEntry( "FSType" );
00824     if ( fstype == "Default" ) // KDE-1 thing
00825       fstype = QString::null;
00826     QString point = cfg.readEntry( "MountPoint" );
00827     (void) new KAutoMount( ro, fstype, dev, point, _url.path() );
00828     retval = -1; // we don't want to return 0, but we don't want to return a pid
00829   }
00830 
00831   return retval;
00832 }
00833 
00834 pid_t KDEDesktopMimeType::runApplication( const KURL& , const QString & _serviceFile )
00835 {
00836   KService s( _serviceFile );
00837   if ( !s.isValid() )
00838     // The error message was already displayed, so we can just quit here
00839     return 0;
00840 
00841   KURL::List lst;
00842   return KRun::run( s, lst );
00843 }
00844 
00845 pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg )
00846 {
00847   QString u = cfg.readPathEntry( "URL" );
00848   if ( u.isEmpty() )
00849   {
00850     QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
00851     KMessageBoxWrapper::error( 0, tmp );
00852     return 0;
00853   }
00854 
00855   KURL url ( u );
00856   KRun* run = new KRun(url);
00857 
00858   // X-KDE-LastOpenedWith holds the service desktop entry name that
00859   // was should be preferred for opening this URL if possible.
00860   // This is used by the Recent Documents menu for instance.
00861   QString lastOpenedWidth = cfg.readEntry( "X-KDE-LastOpenedWith" );
00862   if ( !lastOpenedWidth.isEmpty() )
00863       run->setPreferredService( lastOpenedWidth );
00864 
00865   return -1; // we don't want to return 0, but we don't want to return a pid
00866 }
00867 
00868 pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & )
00869 {
00870   // Hmm, can't really use keditfiletype since we might be looking
00871   // at the global file, or at a file not in share/mimelnk...
00872 
00873   QStringList args;
00874   args << "openProperties";
00875   args << url.path();
00876 
00877   int pid;
00878   if ( !KApplication::kdeinitExec("kfmclient", args, 0, &pid) )
00879       return pid;
00880 
00881   KProcess p;
00882   p << "kfmclient" << args;
00883   p.start(KProcess::DontCare);
00884   return p.pid();
00885 }
00886 
00887 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url )
00888 {
00889   QValueList<Service> result;
00890 
00891   if ( !_url.isLocalFile() )
00892     return result;
00893 
00894   KSimpleConfig cfg( _url.path(), true );
00895   cfg.setDesktopGroup();
00896   QString type = cfg.readEntry( "Type" );
00897 
00898   if ( type.isEmpty() )
00899     return result;
00900 
00901   if ( type == "FSDevice" )
00902   {
00903     QString dev = cfg.readEntry( "Dev" );
00904     if ( dev.isEmpty() )
00905     {
00906       QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00907       KMessageBoxWrapper::error( 0, tmp);
00908     }
00909     else
00910     {
00911       QString mp = KIO::findDeviceMountPoint( dev );
00912       // not mounted ?
00913       if ( mp.isEmpty() )
00914       {
00915     Service mount;
00916     mount.m_strName = i18n("Mount");
00917     mount.m_type = ST_MOUNT;
00918     result.append( mount );
00919       }
00920       else
00921       {
00922     Service unmount;
00923 #ifdef HAVE_VOLMGT
00924     /*
00925      *  Solaris' volume management can only umount+eject
00926      */
00927     unmount.m_strName = i18n("Eject");
00928 #else
00929     unmount.m_strName = i18n("Unmount");
00930 #endif
00931     unmount.m_type = ST_UNMOUNT;
00932     result.append( unmount );
00933       }
00934     }
00935   }
00936 
00937   return result;
00938 }
00939 
00940 QValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const QString& path, bool bLocalFiles )
00941 {
00942   QValueList<Service> result;
00943 
00944   KSimpleConfig cfg( path, true );
00945 
00946   cfg.setDesktopGroup();
00947 
00948   if ( !cfg.hasKey( "Actions" ) )
00949     return result;
00950 
00951   if ( cfg.hasKey( "TryExec" ) )
00952   {
00953       QString tryexec = cfg.readPathEntry( "TryExec" );
00954       QString exe =  KStandardDirs::findExe( tryexec );
00955       if (exe.isEmpty()) {
00956           return result;
00957       }
00958   }
00959 
00960   QStringList keys = cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator!
00961 
00962   if ( keys.count() == 0 )
00963     return result;
00964 
00965   QStringList::ConstIterator it = keys.begin();
00966   QStringList::ConstIterator end = keys.end();
00967   for ( ; it != end; ++it )
00968   {
00969     //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl;
00970 
00971     QString group = *it;
00972 
00973     if (group == "_SEPARATOR_")
00974     {
00975         Service s;
00976         result.append(s);
00977         continue;
00978     }
00979 
00980     group.prepend( "Desktop Action " );
00981 
00982     bool bInvalidMenu = false;
00983 
00984     if ( cfg.hasGroup( group ) )
00985     {
00986       cfg.setGroup( group );
00987 
00988       if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) )
00989         bInvalidMenu = true;
00990       else
00991       {
00992         QString exec = cfg.readPathEntry( "Exec" );
00993         if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") )
00994         {
00995           Service s;
00996           s.m_strName = cfg.readEntry( "Name" );
00997           s.m_strIcon = cfg.readEntry( "Icon" );
00998           s.m_strExec = exec;
00999       s.m_type = ST_USER_DEFINED;
01000           s.m_display = !cfg.readBoolEntry( "NoDisplay" );
01001       result.append( s );
01002         }
01003       }
01004     }
01005     else
01006       bInvalidMenu = true;
01007 
01008     if ( bInvalidMenu )
01009     {
01010       QString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
01011       KMessageBoxWrapper::error( 0, tmp );
01012     }
01013   }
01014 
01015   return result;
01016 }
01017 
01018 void KDEDesktopMimeType::executeService( const QString& _url, KDEDesktopMimeType::Service& _service )
01019 {
01020     KURL u;
01021     u.setPath(_url);
01022     KURL::List lst;
01023     lst.append( u );
01024     executeService( lst, _service );
01025 }
01026 
01027 void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service )
01028 {
01029   //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl;
01030 
01031   if ( _service.m_type == ST_USER_DEFINED )
01032   {
01033     kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName
01034               << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl;
01035     KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
01036     // The action may update the desktop file. Example: eject unmounts (#5129).
01037     KDirNotify_stub allDirNotify("*", "KDirNotify*");
01038     allDirNotify.FilesChanged( urls );
01039     return;
01040   }
01041   else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
01042   {
01043     Q_ASSERT( urls.count() == 1 );
01044     QString path = urls.first().path();
01045     //kdDebug(7009) << "MOUNT&UNMOUNT" << endl;
01046 
01047     KSimpleConfig cfg( path, true );
01048     cfg.setDesktopGroup();
01049     QString dev = cfg.readEntry( "Dev" );
01050     if ( dev.isEmpty() )
01051     {
01052       QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
01053       KMessageBoxWrapper::error( 0, tmp );
01054       return;
01055     }
01056     QString mp = KIO::findDeviceMountPoint( dev );
01057 
01058     if ( _service.m_type == ST_MOUNT )
01059     {
01060       // Already mounted? Strange, but who knows ...
01061       if ( !mp.isEmpty() )
01062       {
01063     kdDebug(7009) << "ALREADY Mounted" << endl;
01064     return;
01065       }
01066 
01067       bool ro = cfg.readBoolEntry( "ReadOnly", false );
01068       QString fstype = cfg.readEntry( "FSType" );
01069       if ( fstype == "Default" ) // KDE-1 thing
01070           fstype = QString::null;
01071       QString point = cfg.readEntry( "MountPoint" );
01072       (void)new KAutoMount( ro, fstype, dev, point, path, false );
01073     }
01074     else if ( _service.m_type == ST_UNMOUNT )
01075     {
01076       // Not mounted? Strange, but who knows ...
01077       if ( mp.isEmpty() )
01078     return;
01079 
01080       (void)new KAutoUnmount( mp, path );
01081     }
01082   }
01083   else
01084     assert( 0 );
01085 }
01086 
01087 const QString & KMimeType::defaultMimeType()
01088 {
01089     static const QString & s_strDefaultMimeType =
01090         KGlobal::staticQString( "application/octet-stream" );
01091     return s_strDefaultMimeType;
01092 }
01093 
01094 void KMimeType::virtual_hook( int id, void* data )
01095 { KServiceType::virtual_hook( id, data ); }
01096 
01097 void KFolderType::virtual_hook( int id, void* data )
01098 { KMimeType::virtual_hook( id, data ); }
01099 
01100 void KDEDesktopMimeType::virtual_hook( int id, void* data )
01101 { KMimeType::virtual_hook( id, data ); }
01102 
01103 void KExecMimeType::virtual_hook( int id, void* data )
01104 { KMimeType::virtual_hook( id, data ); }
01105 
01106 #include "kmimetyperesolver.moc"
01107 
KDE Logo
This file is part of the documentation for kio Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Jan 15 13:33:26 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003