kio Library: kmimetype.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

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

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:00 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003