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