• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kio
 

kio/kio

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., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 // $Id$
00020 
00021 #include <config.h>
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 
00026 #include <assert.h>
00027 #include <dirent.h>
00028 #include <errno.h>
00029 #include <stddef.h>
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032 
00033 #include <kprotocolinfo.h>
00034 #include <kio/global.h>
00035 #include "kmimetype.h"
00036 #include "kservicetypefactory.h"
00037 #include "kmimemagic.h"
00038 #include "kservice.h"
00039 #include "krun.h"
00040 #include "kautomount.h"
00041 #include <kdirnotify_stub.h>
00042 
00043 #include <tqstring.h>
00044 #include <tqfile.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 TQValueList<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      TQString sDefaultMimeType = stdDirs.resourceDirs("mime").first()+defaultMimeType()+".desktop";
00084      s_pDefaultType = new KMimeType( sDefaultMimeType, defaultMimeType(),
00085                                      "unknown", "mime", TQStringList() );
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 TQString& _type )
00135 {
00136   TQString 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 TQString& _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   TQString 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( TQFile::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( TQFile::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   TQString fileName ( _url.fileName() );
00206 
00207   static const TQString& slash = KGlobal::staticQString("/");
00208   if ( ! fileName.isNull() && !path.endsWith( slash ) )
00209   {
00210       // Try to find it out by looking at the filename
00211       KMimeType::Ptr mime = KServiceTypeFactory::self()->findFromPattern( fileName );
00212       if ( mime )
00213       {
00214         // Found something - can we trust it ? (e.g. don't trust *.pl over HTTP, could be anything)
00215         if ( _is_local_file || _url.hasSubURL() || // Explicitly trust suburls
00216              KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) )
00217         {
00218             if ( _is_local_file && !_fast_mode ) {
00219                 if ( mime->patternsAccuracy()<100 )
00220                 {
00221                     KMimeMagicResult* result =
00222                             KMimeMagic::self()->findFileType( path );
00223 
00224                     if ( result && result->isValid() && result->accuracy() > 0 ) {
00225                         KMimeType::Ptr resultMime = mimeType( result->mimeType() );
00226                         if (resultMime->patternsAccuracy() > 0) {
00227                             return resultMime;
00228                         }
00229                     }
00230                 }
00231             }
00232 
00233             return mime;
00234         }
00235       }
00236 
00237       static const TQString& dotdesktop = KGlobal::staticQString(".desktop");
00238       static const TQString& dotkdelnk = KGlobal::staticQString(".kdelnk");
00239       static const TQString& dotdirectory = KGlobal::staticQString(".directory");
00240 
00241       // Another filename binding, hardcoded, is .desktop:
00242       if ( fileName.endsWith( dotdesktop ) )
00243         return mimeType( "application/x-desktop" );
00244       // Another filename binding, hardcoded, is .kdelnk;
00245       // this is preserved for backwards compatibility
00246       if ( fileName.endsWith( dotkdelnk ) )
00247         return mimeType( "application/x-desktop" );
00248       // .directory files are detected as x-desktop by mimemagic
00249       // but don't have a Type= entry. Better cheat and say they are text files
00250       if ( fileName == dotdirectory )
00251         return mimeType( "text/plain" );
00252     }
00253 
00254   if ( !_is_local_file || _fast_mode )
00255   {
00256     TQString def = KProtocolInfo::defaultMimetype( _url );
00257     if ( !def.isEmpty() && def != defaultMimeType() )
00258     {
00259        // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
00260        return mimeType( def );
00261     }
00262     if ( path.endsWith( slash ) || path.isEmpty() )
00263     {
00264       // We have no filename at all. Maybe the protocol has a setting for
00265       // which mimetype this means (e.g. directory).
00266       // For HTTP (def==defaultMimeType()) we don't assume anything,
00267       // because of redirections (e.g. freshmeat downloads).
00268       if ( def.isEmpty() )
00269       {
00270           // Assume inode/directory, if the protocol supports listing.
00271           if ( KProtocolInfo::supportsListing( _url ) )
00272               return mimeType( TQString::fromLatin1("inode/directory") );
00273           else
00274               return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
00275       }
00276     }
00277 
00278     // No more chances for non local URLs
00279     return defaultMimeTypePtr();
00280   }
00281 
00282   // Do some magic for local files
00283   //kdDebug(7009) << TQString("Mime Type finding for '%1'").arg(path) << endl;
00284   KMimeMagicResult* result = KMimeMagic::self()->findFileType( path );
00285 
00286   // If we still did not find it, we must assume the default mime type
00287   if ( !result || !result->isValid() )
00288     return defaultMimeTypePtr();
00289 
00290   // The mimemagic stuff was successful
00291   return mimeType( result->mimeType() );
00292 }
00293 
00294 KMimeType::Ptr KMimeType::findByURL( const KURL& _url, mode_t _mode,
00295                                      bool _is_local_file, bool _fast_mode,
00296                                      bool *accurate)
00297 {
00298     KMimeType::Ptr mime = findByURL(_url, _mode, _is_local_file, _fast_mode);
00299     if (accurate) *accurate = !(_fast_mode) || ((mime->patternsAccuracy() == 100) && mime != defaultMimeTypePtr());
00300     return mime;
00301 }
00302 
00303 KMimeType::Ptr KMimeType::diagnoseFileName(const TQString &fileName, TQString &pattern)
00304 {
00305   return KServiceTypeFactory::self()->findFromPattern( fileName, &pattern );
00306 }
00307 
00308 KMimeType::Ptr KMimeType::findByPath( const TQString& path, mode_t mode, bool fast_mode )
00309 {
00310     KURL u;
00311     u.setPath(path);
00312     return findByURL( u, mode, true, fast_mode );
00313 }
00314 
00315 KMimeType::Ptr KMimeType::findByContent( const TQByteArray &data, int *accuracy )
00316 {
00317   KMimeMagicResult *result = KMimeMagic::self()->findBufferType(data);
00318   if (accuracy)
00319       *accuracy = result->accuracy();
00320   return mimeType( result->mimeType() );
00321 }
00322 
00323 KMimeType::Ptr KMimeType::findByFileContent( const TQString &fileName, int *accuracy )
00324 {
00325   KMimeMagicResult *result = KMimeMagic::self()->findFileType(fileName);
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 TQString &fileName )
00335 {
00336   KMimeType::Format result;
00337   result.compression = Format::NoCompression;
00338   KMimeType::Ptr mime = findByPath(fileName);
00339 
00340   result.text = mime->name().startsWith("text/");
00341   TQVariant v = mime->property("X-KDE-text");
00342   if (v.isValid())
00343      result.text = v.toBool();
00344 
00345   if (mime->name().startsWith("inode/"))
00346      return result;
00347 
00348   TQFile f(fileName);
00349   if (f.open(IO_ReadOnly))
00350   {
00351      unsigned char buf[10+1];
00352      int l = f.readBlock((char *)buf, 10);
00353      if ((l > 2) && (buf[0] == GZIP_MAGIC1) && (buf[1] == GZIP_MAGIC2))
00354         result.compression = Format::GZipCompression;
00355   }
00356   return result;
00357 }
00358 
00359 KMimeType::KMimeType( const TQString & _fullpath, const TQString& _type, const TQString& _icon,
00360                       const TQString& _comment, const TQStringList& _patterns )
00361   : KServiceType( _fullpath, _type, _icon, _comment )
00362 {
00363   m_lstPatterns = _patterns;
00364 }
00365 
00366 KMimeType::KMimeType( const TQString & _fullpath ) : KServiceType( _fullpath )
00367 {
00368   KDesktopFile _cfg( _fullpath, true );
00369   init ( &_cfg );
00370 
00371   if ( !isValid() )
00372     kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
00373 }
00374 
00375 KMimeType::KMimeType( KDesktopFile *config ) : KServiceType( config )
00376 {
00377   init( config );
00378 
00379   if ( !isValid() )
00380     kdWarning(7009) << "mimetype not valid '" << m_strName << "' (missing entry in the file ?)" << endl;
00381 }
00382 
00383 void KMimeType::init( KDesktopFile * config )
00384 {
00385   config->setDesktopGroup();
00386   m_lstPatterns = config->readListEntry( "Patterns", ';' );
00387 
00388   // Read the X-KDE-AutoEmbed setting and store it in the properties map
00389   TQString XKDEAutoEmbed = TQString::fromLatin1("X-KDE-AutoEmbed");
00390   if ( config->hasKey( XKDEAutoEmbed ) )
00391     m_mapProps.insert( XKDEAutoEmbed, TQVariant( config->readBoolEntry( XKDEAutoEmbed ), 0 ) );
00392 
00393   TQString XKDEText = TQString::fromLatin1("X-KDE-text");
00394   if ( config->hasKey( XKDEText ) )
00395     m_mapProps.insert( XKDEText, config->readBoolEntry( XKDEText ) );
00396 
00397   TQString XKDEIsAlso = TQString::fromLatin1("X-KDE-IsAlso");
00398   if ( config->hasKey( XKDEIsAlso ) ) {
00399     TQString inherits = config->readEntry( XKDEIsAlso );
00400     if ( inherits != name() )
00401         m_mapProps.insert( XKDEIsAlso, inherits );
00402     else
00403         kdWarning(7009) << "Error: " << inherits << " inherits from itself!!!!" << endl;
00404   }
00405 
00406   TQString XKDEPatternsAccuracy = TQString::fromLatin1("X-KDE-PatternsAccuracy");
00407   if ( config->hasKey( XKDEPatternsAccuracy ) )
00408     m_mapProps.insert( XKDEPatternsAccuracy, config->readEntry( XKDEPatternsAccuracy ) );
00409 
00410 }
00411 
00412 KMimeType::KMimeType( TQDataStream& _str, int offset ) : KServiceType( _str, offset )
00413 {
00414   loadInternal( _str ); // load our specific stuff
00415 }
00416 
00417 void KMimeType::load( TQDataStream& _str )
00418 {
00419   KServiceType::load( _str );
00420   loadInternal( _str );
00421 }
00422 
00423 void KMimeType::loadInternal( TQDataStream& _str )
00424 {
00425   // kdDebug(7009) << "KMimeType::load( TQDataStream& ) : loading list of patterns" << endl;
00426   _str >> m_lstPatterns;
00427 }
00428 
00429 void KMimeType::save( TQDataStream& _str )
00430 {
00431   KServiceType::save( _str );
00432   // Warning adding/removing fields here involves a binary incompatible change - update version
00433   // number in ksycoca.h
00434   _str << m_lstPatterns;
00435 }
00436 
00437 TQVariant KMimeType::property( const TQString& _name ) const
00438 {
00439   if ( _name == "Patterns" )
00440     return TQVariant( m_lstPatterns );
00441 
00442   return KServiceType::property( _name );
00443 }
00444 
00445 TQStringList KMimeType::propertyNames() const
00446 {
00447   TQStringList res = KServiceType::propertyNames();
00448   res.append( "Patterns" );
00449 
00450   return res;
00451 }
00452 
00453 KMimeType::~KMimeType()
00454 {
00455 }
00456 
00457 TQPixmap KMimeType::pixmap( KIcon::Group _group, int _force_size, int _state,
00458                            TQString * _path ) const
00459 {
00460   KIconLoader *iconLoader=KGlobal::iconLoader();
00461   TQString iconName=icon( TQString::null, false );
00462   if (!iconLoader->extraDesktopThemesAdded())
00463   {
00464     TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
00465     if (!pixmap.isNull() ) return pixmap;
00466 
00467     iconLoader->addExtraDesktopThemes();
00468   }
00469 
00470   return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
00471 }
00472 
00473 TQPixmap KMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
00474                            int _state, TQString * _path ) const
00475 {
00476   KIconLoader *iconLoader=KGlobal::iconLoader();
00477   TQString iconName=icon( _url, _url.isLocalFile() );
00478   if (!iconLoader->extraDesktopThemesAdded())
00479   {
00480     TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
00481     if (!pixmap.isNull() ) return pixmap;
00482 
00483     iconLoader->addExtraDesktopThemes();
00484   }
00485 
00486   return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
00487 }
00488 
00489 TQPixmap KMimeType::pixmapForURL( const KURL & _url, mode_t _mode, KIcon::Group _group,
00490                                  int _force_size, int _state, TQString * _path )
00491 {
00492   KIconLoader *iconLoader=KGlobal::iconLoader();
00493   TQString iconName = iconForURL( _url, _mode );
00494 
00495   if (!iconLoader->extraDesktopThemesAdded())
00496   {
00497     TQPixmap pixmap=iconLoader->loadIcon( iconName, _group, _force_size, _state, _path, true );
00498     if (!pixmap.isNull() ) return pixmap;
00499 
00500     iconLoader->addExtraDesktopThemes();
00501   }
00502 
00503   return iconLoader->loadIcon( iconName , _group, _force_size, _state, _path, false );
00504 
00505 }
00506 
00507 TQString KMimeType::iconForURL( const KURL & _url, mode_t _mode )
00508 {
00509     const KMimeType::Ptr mt = findByURL( _url, _mode, _url.isLocalFile(),
00510                                          false /*HACK*/);
00511     static const TQString& unknown = KGlobal::staticQString("unknown");
00512     const TQString mimeTypeIcon = mt->icon( _url, _url.isLocalFile() );
00513     TQString i = mimeTypeIcon;
00514 
00515     // if we don't find an icon, maybe we can use the one for the protocol
00516     if ( i == unknown || i.isEmpty() || mt == defaultMimeTypePtr()
00517         // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
00518         || _url.path().length() <= 1 )
00519     {
00520         i = favIconForURL( _url ); // maybe there is a favicon?
00521 
00522         if ( i.isEmpty() )
00523             i = KProtocolInfo::icon( _url.protocol() );
00524 
00525         // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
00526         if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
00527             i = mimeTypeIcon;
00528 
00529         // special case: root directory (/) -- Gitea issue #128
00530         if ( _url == KURL("file:///") )
00531             i = "folder_red";
00532     }
00533     return i;
00534 }
00535 
00536 TQString KMimeType::favIconForURL( const KURL& url )
00537 {
00538     // this method will be called quite often, so better not read the config
00539     // again and again.
00540     static bool useFavIcons = true;
00541     static bool check = true;
00542     if ( check ) {
00543         check = false;
00544         KConfig *config = KGlobal::config();
00545         KConfigGroupSaver cs( config, "HTML Settings" );
00546         useFavIcons = config->readBoolEntry( "EnableFavicon", true );
00547     }
00548 
00549     if ( url.isLocalFile() || !url.protocol().startsWith("http")
00550          || !useFavIcons )
00551         return TQString::null;
00552 
00553     DCOPRef kded( "kded", "favicons" );
00554     DCOPReply result = kded.call( "iconForURL(KURL)", url );
00555     if ( result.isValid() )
00556         return result;
00557 
00558     return TQString::null;
00559 }
00560 
00561 TQString KMimeType::parentMimeType() const
00562 {
00563   TQVariant v = property("X-KDE-IsAlso");
00564   return v.toString();
00565 }
00566 
00567 bool KMimeType::is( const TQString& mimeTypeName ) const
00568 {
00569   if ( name() == mimeTypeName )
00570       return true;
00571   TQString st = parentMimeType();
00572   //if (st.isEmpty()) kdDebug(7009)<<"Parent mimetype is empty"<<endl;
00573   while ( !st.isEmpty() )
00574   {
00575       //kdDebug(7009)<<"Checking parent mime type: "<<st<<endl;
00576       KMimeType::Ptr ptr = KMimeType::mimeType( st );
00577       if (!ptr) return false; //error
00578       if ( ptr->name() == mimeTypeName )
00579           return true;
00580       st = ptr->parentMimeType();
00581   }
00582   return false;
00583 }
00584 
00585 int KMimeType::patternsAccuracy() const {
00586   TQVariant v = property("X-KDE-PatternsAccuracy");
00587   if (!v.isValid()) return 100;
00588   else
00589       return v.toInt();
00590 }
00591 
00592 
00593 /*******************************************************
00594  *
00595  * KFolderType
00596  *
00597  ******************************************************/
00598 
00599 TQString KFolderType::icon( const TQString& _url, bool _is_local ) const
00600 {
00601   if ( !_is_local || _url.isEmpty() )
00602     return KMimeType::icon( _url, _is_local );
00603 
00604   return KFolderType::icon( KURL(_url), _is_local );
00605 }
00606 
00607 TQString KFolderType::icon( const KURL& _url, bool _is_local ) const
00608 {
00609   if ( !_is_local )
00610     return KMimeType::icon( _url, _is_local );
00611 
00612   KURL u( _url );
00613   u.addPath( ".directory" );
00614 
00615   TQString icon;
00616   // using KStandardDirs as this one checks for path being
00617   // a file instead of a directory
00618   if ( KStandardDirs::exists( u.path() ) )
00619   {
00620     KSimpleConfig cfg( u.path(), true );
00621     cfg.setDesktopGroup();
00622     icon = cfg.readEntry( "Icon" );
00623     TQString empty_icon = cfg.readEntry( "EmptyIcon" );
00624 
00625     if ( !empty_icon.isEmpty() )
00626     {
00627       bool isempty = false;
00628       DIR *dp = 0L;
00629       struct dirent *ep;
00630       dp = opendir( TQFile::encodeName(_url.path()) );
00631       if ( dp )
00632       {
00633         TQValueList<TQCString> entries;
00634         // Note that readdir isn't guaranteed to return "." and ".." first (#79826)
00635         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00636         ep=readdir( dp ); if ( ep ) entries.append( ep->d_name );
00637         if ( (ep=readdir( dp )) == 0L ) // third file is NULL entry -> empty directory
00638           isempty = true;
00639         else {
00640           entries.append( ep->d_name );
00641           if ( readdir( dp ) == 0 ) { // only three
00642             // check if we got "." ".." and ".directory"
00643             isempty = entries.find( "." ) != entries.end() &&
00644                       entries.find( ".." ) != entries.end() &&
00645                       entries.find( ".directory" ) != entries.end();
00646           }
00647         }
00648         if (!isempty && !strcmp(ep->d_name, ".directory"))
00649           isempty = (readdir(dp) == 0L);
00650         closedir( dp );
00651       }
00652 
00653       if ( isempty )
00654         return empty_icon;
00655     }
00656   }
00657 
00658   if ( icon.isEmpty() )
00659     return KMimeType::icon( _url, _is_local );
00660 
00661   if ( icon.startsWith( "./" ) ) {
00662     // path is relative with respect to the location
00663     // of the .directory file (#73463)
00664     KURL v( _url );
00665     v.addPath( icon.mid( 2 ) );
00666     icon = v.path();
00667   }
00668 
00669   return icon;
00670 }
00671 
00672 TQString KFolderType::comment( const TQString& _url, bool _is_local ) const
00673 {
00674   if ( !_is_local || _url.isEmpty() )
00675     return KMimeType::comment( _url, _is_local );
00676 
00677   return KFolderType::comment( KURL(_url), _is_local );
00678 }
00679 
00680 TQString KFolderType::comment( const KURL& _url, bool _is_local ) const
00681 {
00682   if ( !_is_local )
00683     return KMimeType::comment( _url, _is_local );
00684 
00685   KURL u( _url );
00686   u.addPath( ".directory" );
00687 
00688   KDesktopFile cfg( u.path(), true );
00689   TQString comment = cfg.readComment();
00690   if ( comment.isEmpty() )
00691     return KMimeType::comment( _url, _is_local );
00692 
00693   return comment;
00694 }
00695 
00696 /*******************************************************
00697  *
00698  * KDEDesktopMimeType
00699  *
00700  ******************************************************/
00701 
00702 TQString KDEDesktopMimeType::icon( const TQString& _url, bool _is_local ) const
00703 {
00704   if ( !_is_local || _url.isEmpty() )
00705     return KMimeType::icon( _url, _is_local );
00706 
00707   KURL u( _url );
00708   return icon( u, _is_local );
00709 }
00710 
00711 TQString KDEDesktopMimeType::icon( const KURL& _url, bool _is_local ) const
00712 {
00713   if ( !_is_local )
00714     return KMimeType::icon( _url, _is_local );
00715 
00716   KSimpleConfig cfg( _url.path(), true );
00717   cfg.setDesktopGroup();
00718   TQString icon = cfg.readEntry( "Icon" );
00719   TQString type = cfg.readEntry( "Type" );
00720 
00721   if ( type == "FSDevice" || type == "FSDev") // need to provide FSDev for
00722                                               // backwards compatibility
00723   {
00724     TQString unmount_icon = cfg.readEntry( "UnmountIcon" );
00725     TQString dev = cfg.readEntry( "Dev" );
00726     if ( !icon.isEmpty() && !unmount_icon.isEmpty() && !dev.isEmpty() )
00727     {
00728       TQString mp = KIO::findDeviceMountPoint( dev );
00729       // Is the device not mounted ?
00730       if ( mp.isNull() )
00731         return unmount_icon;
00732     }
00733   } else if ( type == "Link" ) {
00734       const TQString emptyIcon = cfg.readEntry( "EmptyIcon" );
00735       if ( !emptyIcon.isEmpty() ) {
00736           const TQString u = cfg.readPathEntry( "URL" );
00737           const KURL url( u );
00738           if ( url.protocol() == "trash" ) {
00739               // We need to find if the trash is empty, preferrably without using a KIO job.
00740               // So instead kio_trash leaves an entry in its config file for us.
00741               KSimpleConfig trashConfig( "trashrc", true );
00742               trashConfig.setGroup( "Status" );
00743               if ( trashConfig.readBoolEntry( "Empty", true ) ) {
00744                   return emptyIcon;
00745               }
00746           }
00747       }
00748   }
00749 
00750   if ( icon.isEmpty() )
00751     return KMimeType::icon( _url, _is_local );
00752 
00753   return icon;
00754 }
00755 
00756 TQPixmap KDEDesktopMimeType::pixmap( const KURL& _url, KIcon::Group _group, int _force_size,
00757                                     int _state, TQString * _path ) const
00758 {
00759   TQString _icon = icon( _url, _url.isLocalFile() );
00760   TQPixmap pix = KGlobal::iconLoader()->loadIcon( _icon, _group,
00761         _force_size, _state, _path, false );
00762   if ( pix.isNull() )
00763       pix = KGlobal::iconLoader()->loadIcon( "unknown", _group,
00764         _force_size, _state, _path, false );
00765   return pix;
00766 }
00767 
00768 TQString KDEDesktopMimeType::comment( const TQString& _url, bool _is_local ) const
00769 {
00770   if ( !_is_local || _url.isEmpty() )
00771     return KMimeType::comment( _url, _is_local );
00772 
00773   KURL u( _url );
00774   return comment( u, _is_local );
00775 }
00776 
00777 TQString KDEDesktopMimeType::comment( const KURL& _url, bool _is_local ) const
00778 {
00779   if ( !_is_local )
00780     return KMimeType::comment( _url, _is_local );
00781 
00782   KDesktopFile cfg( _url.path(), true );
00783   TQString comment = cfg.readComment();
00784   if ( comment.isEmpty() )
00785     return KMimeType::comment( _url, _is_local );
00786 
00787   return comment;
00788 }
00789 
00790 pid_t KDEDesktopMimeType::run( const KURL& u, bool _is_local )
00791 {
00792   // It might be a security problem to run external untrusted desktop
00793   // entry files
00794   if ( !_is_local )
00795     return 0;
00796 
00797   KSimpleConfig cfg( u.path(), true );
00798   cfg.setDesktopGroup();
00799   TQString type = cfg.readEntry( "Type" );
00800   if ( type.isEmpty() )
00801   {
00802     TQString tmp = i18n("The desktop entry file %1 "
00803                        "has no Type=... entry.").arg(u.path() );
00804     KMessageBoxWrapper::error( 0, tmp);
00805     return 0;
00806   }
00807 
00808   //kdDebug(7009) << "TYPE = " << type.data() << endl;
00809 
00810   if ( type == "FSDevice" )
00811     return runFSDevice( u, cfg );
00812   else if ( type == "Application" )
00813     return runApplication( u, u.path() );
00814   else if ( type == "Link" )
00815   {
00816     cfg.setDollarExpansion( true ); // for URL=file:$HOME (Simon)
00817     return runLink( u, cfg );
00818   }
00819   else if ( type == "MimeType" )
00820     return runMimeType( u, cfg );
00821 
00822 
00823   TQString tmp = i18n("The desktop entry of type\n%1\nis unknown.").arg( type );
00824   KMessageBoxWrapper::error( 0, tmp);
00825 
00826   return 0;
00827 }
00828 
00829 pid_t KDEDesktopMimeType::runFSDevice( const KURL& _url, const KSimpleConfig &cfg )
00830 {
00831   pid_t retval = 0;
00832 
00833   TQString dev = cfg.readEntry( "Dev" );
00834 
00835   if ( dev.isEmpty() )
00836   {
00837     TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00838     KMessageBoxWrapper::error( 0, tmp);
00839     return retval;
00840   }
00841 
00842   TQString mp = KIO::findDeviceMountPoint( dev );
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, TQString::fromLatin1("inode/directory") );
00850   }
00851   else
00852   {
00853     bool ro = cfg.readBoolEntry( "ReadOnly", false );
00854     TQString fstype = cfg.readEntry( "FSType" );
00855     if ( fstype == "Default" ) // KDE-1 thing
00856       fstype = TQString::null;
00857     TQString point = cfg.readEntry( "MountPoint" );
00858 #ifndef Q_WS_WIN
00859     (void) new KAutoMount( ro, fstype, dev, point, _url.path() );
00860 #endif
00861     retval = -1; // we don't want to return 0, but we don't want to return a pid
00862   }
00863 
00864   return retval;
00865 }
00866 
00867 pid_t KDEDesktopMimeType::runApplication( const KURL& , const TQString & _serviceFile )
00868 {
00869   KService s( _serviceFile );
00870   if ( !s.isValid() )
00871     // The error message was already displayed, so we can just quit here
00872     return 0;
00873 
00874   KURL::List lst;
00875   return KRun::run( s, lst );
00876 }
00877 
00878 pid_t KDEDesktopMimeType::runLink( const KURL& _url, const KSimpleConfig &cfg )
00879 {
00880   TQString u = cfg.readPathEntry( "URL" );
00881   if ( u.isEmpty() )
00882   {
00883     TQString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.").arg( _url.prettyURL() );
00884     KMessageBoxWrapper::error( 0, tmp );
00885     return 0;
00886   }
00887 
00888   KURL url ( u );
00889   KRun* run = new KRun(url);
00890 
00891   // X-KDE-LastOpenedWith holds the service desktop entry name that
00892   // was should be preferred for opening this URL if possible.
00893   // This is used by the Recent Documents menu for instance.
00894   TQString lastOpenedWidth = cfg.readEntry( "X-KDE-LastOpenedWith" );
00895   if ( !lastOpenedWidth.isEmpty() )
00896       run->setPreferredService( lastOpenedWidth );
00897 
00898   return -1; // we don't want to return 0, but we don't want to return a pid
00899 }
00900 
00901 pid_t KDEDesktopMimeType::runMimeType( const KURL& url , const KSimpleConfig & )
00902 {
00903   // Hmm, can't really use keditfiletype since we might be looking
00904   // at the global file, or at a file not in share/mimelnk...
00905 
00906   TQStringList args;
00907   args << "openProperties";
00908   args << url.path();
00909 
00910   int pid;
00911   if ( !KApplication::kdeinitExec("kfmclient", args, 0, &pid) )
00912       return pid;
00913 
00914   KProcess p;
00915   p << "kfmclient" << args;
00916   p.start(KProcess::DontCare);
00917   return p.pid();
00918 }
00919 
00920 TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::builtinServices( const KURL& _url )
00921 {
00922   TQValueList<Service> result;
00923 
00924   if ( !_url.isLocalFile() )
00925     return result;
00926 
00927   KSimpleConfig cfg( _url.path(), true );
00928   cfg.setDesktopGroup();
00929   TQString type = cfg.readEntry( "Type" );
00930 
00931   if ( type.isEmpty() )
00932     return result;
00933 
00934   if ( type == "FSDevice" )
00935   {
00936     TQString dev = cfg.readEntry( "Dev" );
00937     if ( dev.isEmpty() )
00938     {
00939       TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( _url.path() );
00940       KMessageBoxWrapper::error( 0, tmp);
00941     }
00942     else
00943     {
00944       TQString mp = KIO::findDeviceMountPoint( dev );
00945       // not mounted ?
00946       if ( mp.isEmpty() )
00947       {
00948         Service mount;
00949         mount.m_strName = i18n("Mount");
00950         mount.m_type = ST_MOUNT;
00951         result.append( mount );
00952       }
00953       else
00954       {
00955         Service unmount;
00956 #ifdef HAVE_VOLMGT
00957         /*
00958          *  Solaris' volume management can only umount+eject
00959          */
00960         unmount.m_strName = i18n("Eject");
00961 #else
00962         unmount.m_strName = i18n("Unmount");
00963 #endif
00964         unmount.m_type = ST_UNMOUNT;
00965         result.append( unmount );
00966       }
00967     }
00968   }
00969 
00970   return result;
00971 }
00972 
00973 TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, bool bLocalFiles )
00974 {
00975   KSimpleConfig cfg( path, true );
00976   return userDefinedServices( path, cfg, bLocalFiles );
00977 }
00978 
00979 TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, KConfig& cfg, bool bLocalFiles )
00980 {
00981  return userDefinedServices( path, cfg, bLocalFiles, KURL::List() );
00982 }
00983 
00984 TQValueList<KDEDesktopMimeType::Service> KDEDesktopMimeType::userDefinedServices( const TQString& path, KConfig& cfg, bool bLocalFiles, const KURL::List & file_list )
00985 {
00986   TQValueList<Service> result;
00987 
00988   cfg.setDesktopGroup();
00989 
00990   if ( !cfg.hasKey( "Actions" ) && !cfg.hasKey( "X-KDE-GetActionMenu") )
00991     return result;
00992 
00993   if ( cfg.hasKey( "TryExec" ) )
00994   {
00995       TQString tryexec = cfg.readPathEntry( "TryExec" );
00996       TQString exe =  KStandardDirs::findExe( tryexec );
00997       if (exe.isEmpty()) {
00998           return result;
00999       }
01000   }
01001 
01002   TQStringList keys;
01003 
01004   if( cfg.hasKey( "X-KDE-GetActionMenu" )) {
01005     TQString dcopcall = cfg.readEntry( "X-KDE-GetActionMenu" );
01006     const TQCString app = TQString(dcopcall.section(' ', 0,0)).utf8();
01007 
01008     TQByteArray dataToSend;
01009     TQDataStream dataStream(dataToSend, IO_WriteOnly);
01010     dataStream << file_list;
01011     TQCString replyType;
01012     TQByteArray replyData;
01013     TQCString object = TQString(dcopcall.section(' ', 1,-2)).utf8();
01014     TQString function = dcopcall.section(' ', -1);
01015     if(!function.endsWith("(KURL::List)")) {
01016       kdWarning() << "Desktop file " << path << " contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
01017     } else {
01018       if(kapp->dcopClient()->call( app, object,
01019                    function.utf8(),
01020                    dataToSend, replyType, replyData, true, -1)
01021         && replyType == "TQStringList" ) {
01022 
01023         TQDataStream dataStreamIn(replyData, IO_ReadOnly);
01024         dataStreamIn >> keys;
01025       }
01026     }
01027   }
01028 
01029   keys += cfg.readListEntry( "Actions", ';' ); //the desktop standard defines ";" as separator!
01030 
01031   if ( keys.count() == 0 )
01032     return result;
01033 
01034   TQStringList::ConstIterator it = keys.begin();
01035   TQStringList::ConstIterator end = keys.end();
01036   for ( ; it != end; ++it )
01037   {
01038     //kdDebug(7009) << "CURRENT KEY = " << (*it) << endl;
01039 
01040     TQString group = *it;
01041 
01042     if (group == "_SEPARATOR_")
01043     {
01044         Service s;
01045         result.append(s);
01046         continue;
01047     }
01048 
01049     group.prepend( "Desktop Action " );
01050 
01051     bool bInvalidMenu = false;
01052 
01053     if ( cfg.hasGroup( group ) )
01054     {
01055       cfg.setGroup( group );
01056 
01057       if ( !cfg.hasKey( "Name" ) || !cfg.hasKey( "Exec" ) )
01058         bInvalidMenu = true;
01059       else
01060       {
01061         TQString exec = cfg.readPathEntry( "Exec" );
01062         if ( bLocalFiles || exec.contains("%U") || exec.contains("%u") )
01063         {
01064           Service s;
01065           s.m_strName = cfg.readEntry( "Name" );
01066           s.m_strIcon = cfg.readEntry( "Icon" );
01067           s.m_strExec = exec;
01068           s.m_type = ST_USER_DEFINED;
01069           s.m_display = !cfg.readBoolEntry( "NoDisplay" );
01070           result.append( s );
01071         }
01072       }
01073     }
01074     else
01075       bInvalidMenu = true;
01076 
01077     if ( bInvalidMenu )
01078     {
01079       TQString tmp = i18n("The desktop entry file\n%1\n has an invalid menu entry\n%2.").arg( path ).arg( *it );
01080       KMessageBoxWrapper::error( 0, tmp );
01081     }
01082   }
01083 
01084   return result;
01085 }
01086 
01087 void KDEDesktopMimeType::executeService( const TQString& _url, KDEDesktopMimeType::Service& _service )
01088 {
01089     KURL u;
01090     u.setPath(_url);
01091     KURL::List lst;
01092     lst.append( u );
01093     executeService( lst, _service );
01094 }
01095 
01096 void KDEDesktopMimeType::executeService( const KURL::List& urls, KDEDesktopMimeType::Service& _service )
01097 {
01098   //kdDebug(7009) << "EXECUTING Service " << _service.m_strName << endl;
01099 
01100   if ( _service.m_type == ST_USER_DEFINED )
01101   {
01102     kdDebug() << "KDEDesktopMimeType::executeService " << _service.m_strName
01103               << " first url's path=" << urls.first().path() << " exec=" << _service.m_strExec << endl;
01104     KRun::run( _service.m_strExec, urls, _service.m_strName, _service.m_strIcon, _service.m_strIcon );
01105     // The action may update the desktop file. Example: eject unmounts (#5129).
01106     KDirNotify_stub allDirNotify("*", "KDirNotify*");
01107     allDirNotify.FilesChanged( urls );
01108     return;
01109   }
01110   else if ( _service.m_type == ST_MOUNT || _service.m_type == ST_UNMOUNT )
01111   {
01112     Q_ASSERT( urls.count() == 1 );
01113     TQString path = urls.first().path();
01114     //kdDebug(7009) << "MOUNT&UNMOUNT" << endl;
01115 
01116     KSimpleConfig cfg( path, true );
01117     cfg.setDesktopGroup();
01118     TQString dev = cfg.readEntry( "Dev" );
01119     if ( dev.isEmpty() )
01120     {
01121       TQString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.").arg( path );
01122       KMessageBoxWrapper::error( 0, tmp );
01123       return;
01124     }
01125     TQString mp = KIO::findDeviceMountPoint( dev );
01126 
01127     if ( _service.m_type == ST_MOUNT )
01128     {
01129       // Already mounted? Strange, but who knows ...
01130       if ( !mp.isEmpty() )
01131       {
01132         kdDebug(7009) << "ALREADY Mounted" << endl;
01133         return;
01134       }
01135 
01136       bool ro = cfg.readBoolEntry( "ReadOnly", false );
01137       TQString fstype = cfg.readEntry( "FSType" );
01138       if ( fstype == "Default" ) // KDE-1 thing
01139           fstype = TQString::null;
01140       TQString point = cfg.readEntry( "MountPoint" );
01141 #ifndef Q_WS_WIN
01142       (void)new KAutoMount( ro, fstype, dev, point, path, false );
01143 #endif
01144     }
01145     else if ( _service.m_type == ST_UNMOUNT )
01146     {
01147       // Not mounted? Strange, but who knows ...
01148       if ( mp.isEmpty() )
01149         return;
01150 
01151 #ifndef Q_WS_WIN
01152       (void)new KAutoUnmount( mp, path );
01153 #endif
01154     }
01155   }
01156   else
01157     assert( 0 );
01158 }
01159 
01160 const TQString & KMimeType::defaultMimeType()
01161 {
01162     static const TQString & s_strDefaultMimeType =
01163         KGlobal::staticQString( "application/octet-stream" );
01164     return s_strDefaultMimeType;
01165 }
01166 
01167 void KMimeType::virtual_hook( int id, void* data )
01168 { KServiceType::virtual_hook( id, data ); }
01169 
01170 void KFolderType::virtual_hook( int id, void* data )
01171 { KMimeType::virtual_hook( id, data ); }
01172 
01173 void KDEDesktopMimeType::virtual_hook( int id, void* data )
01174 { KMimeType::virtual_hook( id, data ); }
01175 
01176 void KExecMimeType::virtual_hook( int id, void* data )
01177 { KMimeType::virtual_hook( id, data ); }
01178 
01179 #include "kmimetyperesolver.moc"
01180 

kio/kio

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

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |