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